init
This commit is contained in:
50
HTS_Alert.py
50
HTS_Alert.py
@@ -1,50 +0,0 @@
|
||||
import time
|
||||
import requests
|
||||
from bs4 import BeautifulSoup
|
||||
from datetime import datetime
|
||||
from stock.util.TelegramBot import TelegramBot
|
||||
|
||||
class HTS_Alert :
|
||||
bot = None
|
||||
|
||||
def __init__(self):
|
||||
self.bot = TelegramBot()
|
||||
return
|
||||
|
||||
def checkPrice(self, code):
|
||||
code_index = 0
|
||||
PERCENT = ["50%", "50%"]
|
||||
CHECK_PRICE = [2565, 2422]
|
||||
|
||||
THIS_TIME = datetime.now()
|
||||
today = datetime.today().strftime('%Y%m%d')
|
||||
while datetime.strptime(today + " 080000", '%Y%m%d %H%M%S') < THIS_TIME < datetime.strptime(today + " 151500", '%Y%m%d %H%M%S'):
|
||||
url = 'https://finance.naver.com/item/main.naver?code={code}'.format(code=code.strip())
|
||||
res = requests.get(url)
|
||||
|
||||
html = res.text
|
||||
soup = BeautifulSoup(html, 'html.parser')
|
||||
post = soup.select_one('#chart_area > .rate_info > .today > .no_today > em')
|
||||
arr = post.text.split("\n")
|
||||
c_price = int(arr[1].replace(',', ''))
|
||||
|
||||
if c_price < CHECK_PRICE[code_index]:
|
||||
self.bot.sendMsg(code + " " + str(CHECK_PRICE[code_index]) + " " + PERCENT[code_index] + "를 파세요...")
|
||||
code_index += 1
|
||||
|
||||
if code_index > len(CHECK_PRICE):
|
||||
break
|
||||
|
||||
time.sleep(60)
|
||||
THIS_TIME = datetime.now()
|
||||
return
|
||||
|
||||
if __name__ == "__main__":
|
||||
hTS_Alert = HTS_Alert()
|
||||
|
||||
week = datetime.today().weekday()
|
||||
if week in (0, 1, 2, 3, 4): # 0:월, 1:화, 2:수, 3:목, 4:금, 5:토, 6:일
|
||||
|
||||
post = hTS_Alert.checkPrice('252670')
|
||||
|
||||
print ("done...")
|
||||
@@ -1,31 +0,0 @@
|
||||
import os
|
||||
from datetime import datetime
|
||||
from HTS_etf import HTS_etf
|
||||
|
||||
if __name__ == "__main__":
|
||||
today = datetime.today()
|
||||
|
||||
PROJECT_HOME = os.getcwd()
|
||||
RESOURCE_PATH = os.path.join(PROJECT_HOME, "resources")
|
||||
|
||||
# KODEX 인버스 * 2
|
||||
stock_code = "122630"
|
||||
stock_name = "KODEX 레버리지"
|
||||
|
||||
hts = HTS_etf(RESOURCE_PATH, stock_code, stock_name, SELL_GAP=80)
|
||||
hts.connect2DB("hts.db")
|
||||
|
||||
today_str = today.strftime('%Y%m%d')
|
||||
|
||||
if not os.path.exists(os.path.join(RESOURCE_PATH, "log")):
|
||||
os.mkdir(os.path.join(RESOURCE_PATH, "log"))
|
||||
|
||||
MAX_PRICE = 500000
|
||||
hts.buyRealTime(today_str, MAX_PRICE=MAX_PRICE)
|
||||
|
||||
db_filename = os.path.join(RESOURCE_PATH, "hts.db")
|
||||
hts.insertStockData(today, stock_code, stock_name)
|
||||
|
||||
hts.disconnect()
|
||||
hts.bot.sendMsg("done... {} ({})".format(stock_code, stock_name))
|
||||
print("done...")
|
||||
@@ -1,31 +0,0 @@
|
||||
import os
|
||||
from datetime import datetime
|
||||
from HTS_etf import HTS_etf
|
||||
|
||||
if __name__ == "__main__":
|
||||
today = datetime.today()
|
||||
|
||||
PROJECT_HOME = os.getcwd()
|
||||
RESOURCE_PATH = os.path.join(PROJECT_HOME, "resources")
|
||||
|
||||
# KODEX 인버스 * 2
|
||||
stock_code = "233740"
|
||||
stock_name = "KODEX 코스닥150레버리지"
|
||||
|
||||
hts = HTS_etf(RESOURCE_PATH, stock_code, stock_name, SELL_GAP=70)
|
||||
hts.connect2DB("hts.db")
|
||||
|
||||
today_str = today.strftime('%Y%m%d')
|
||||
|
||||
if not os.path.exists(os.path.join(RESOURCE_PATH, "log")):
|
||||
os.mkdir(os.path.join(RESOURCE_PATH, "log"))
|
||||
|
||||
MAX_PRICE = 500000
|
||||
hts.buyRealTime(today_str, MAX_PRICE=MAX_PRICE)
|
||||
|
||||
db_filename = os.path.join(RESOURCE_PATH, "hts.db")
|
||||
hts.insertStockData(today, stock_code, stock_name)
|
||||
|
||||
hts.disconnect()
|
||||
hts.bot.sendMsg("done... {} ({})".format(stock_code, stock_name))
|
||||
print("done...")
|
||||
@@ -1,31 +0,0 @@
|
||||
import os
|
||||
from datetime import datetime
|
||||
from HTS_etf import HTS_etf
|
||||
|
||||
if __name__ == "__main__":
|
||||
today = datetime.today()
|
||||
|
||||
PROJECT_HOME = os.getcwd()
|
||||
RESOURCE_PATH = os.path.join(PROJECT_HOME, "resources")
|
||||
|
||||
# KODEX 인버스 * 2
|
||||
stock_code = "251340"
|
||||
stock_name = "KODEX 코스닥150선물인버스"
|
||||
|
||||
hts = HTS_etf(RESOURCE_PATH, stock_code, stock_name, SELL_GAP=50)
|
||||
hts.connect2DB("hts.db")
|
||||
|
||||
today_str = today.strftime('%Y%m%d')
|
||||
|
||||
if not os.path.exists(os.path.join(RESOURCE_PATH, "log")):
|
||||
os.mkdir(os.path.join(RESOURCE_PATH, "log"))
|
||||
|
||||
MAX_PRICE = 500000
|
||||
hts.buyRealTime(today_str, MAX_PRICE=MAX_PRICE)
|
||||
|
||||
db_filename = os.path.join(RESOURCE_PATH, "hts.db")
|
||||
hts.insertStockData(today, stock_code, stock_name)
|
||||
|
||||
hts.disconnect()
|
||||
hts.bot.sendMsg("done... {} ({})".format(stock_code, stock_name))
|
||||
print("done...")
|
||||
@@ -1,31 +0,0 @@
|
||||
import os
|
||||
from datetime import datetime
|
||||
from HTS_etf import HTS_etf
|
||||
|
||||
if __name__ == "__main__":
|
||||
today = datetime.today()
|
||||
|
||||
PROJECT_HOME = os.getcwd()
|
||||
RESOURCE_PATH = os.path.join(PROJECT_HOME, "resources")
|
||||
|
||||
# KODEX 인버스 * 2
|
||||
stock_code = "252670"
|
||||
stock_name = "KODEX 200선물인버스2X"
|
||||
|
||||
hts = HTS_etf(RESOURCE_PATH, stock_code, stock_name, SELL_GAP=30)
|
||||
hts.connect2DB("hts.db")
|
||||
|
||||
today_str = today.strftime('%Y%m%d')
|
||||
|
||||
if not os.path.exists(os.path.join(RESOURCE_PATH, "log")):
|
||||
os.mkdir(os.path.join(RESOURCE_PATH, "log"))
|
||||
|
||||
MAX_PRICE = 500000
|
||||
hts.buyRealTime(today_str, MAX_PRICE=MAX_PRICE)
|
||||
|
||||
db_filename = os.path.join(RESOURCE_PATH, "hts.db")
|
||||
hts.insertStockData(today, stock_code, stock_name)
|
||||
|
||||
hts.disconnect()
|
||||
hts.bot.sendMsg("done... {} ({})".format(stock_code, stock_name))
|
||||
print("done...")
|
||||
@@ -1,80 +0,0 @@
|
||||
import os
|
||||
import json
|
||||
import time
|
||||
import psutil
|
||||
from datetime import datetime
|
||||
from HTS_etf import HTS_etf
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
PROJECT_HOME = os.getcwd()
|
||||
RESOURCE_PATH = os.path.join(PROJECT_HOME, "resources")
|
||||
|
||||
stocks = [
|
||||
{'stock_code': '122630', 'stock_name': 'KODEX 레버리지'},
|
||||
{'stock_code': '233740', 'stock_name': 'KODEX 코스닥150레버리지'},
|
||||
{'stock_code': '251340', 'stock_name': 'KODEX 코스닥150선물인버스'},
|
||||
{'stock_code': '252670', 'stock_name': 'KODEX 200선물인버스2X'}
|
||||
]
|
||||
|
||||
hts = HTS_etf(RESOURCE_PATH)
|
||||
hts.connect2DB("hts.db")
|
||||
|
||||
today = datetime.today().strftime('%Y%m%d')
|
||||
|
||||
if not os.path.exists(os.path.join(RESOURCE_PATH, "log")):
|
||||
os.mkdir(os.path.join(RESOURCE_PATH, "log"))
|
||||
|
||||
BUY_LIST = {}
|
||||
for stock in stocks:
|
||||
with open("config.json", "r", encoding="utf-8") as f:
|
||||
config = json.load(f)
|
||||
|
||||
if stock['stock_code'] not in BUY_LIST:
|
||||
BUY_LIST[stock['stock_code']] = {}
|
||||
|
||||
BUY_LIST[stock['stock_code']]['MAX_BUY_PRICE'] = config['MAX_BUY_PRICE']
|
||||
BUY_LIST[stock['stock_code']]['BUY_LIST_1'] = config['BUY_LIST_1']
|
||||
BUY_LIST[stock['stock_code']]['BUY_LIST_1']["disparity"] = hts.getDisparityLimit(stock)
|
||||
|
||||
print("START...")
|
||||
close_data = {}
|
||||
INIT = True
|
||||
while datetime.strptime(today + " 060000", '%Y%m%d %H%M%S') < datetime.now() < datetime.strptime(today + " 153100", '%Y%m%d %H%M%S'):
|
||||
if datetime.strptime(today + " 090000", '%Y%m%d %H%M%S') < datetime.now() < datetime.strptime(today + " 151500", '%Y%m%d %H%M%S'):
|
||||
THIS_TIME = datetime.now()
|
||||
for stock in stocks:
|
||||
if datetime.strptime(today + " 090000", '%Y%m%d %H%M%S') < datetime.now() < datetime.strptime(today + " 090100", '%Y%m%d %H%M%S'):
|
||||
hts.bot.sendMsg("START... {} ({}) SLOW_K: {}".format(stock['stock_code'], stock['stock_name'], BUY_LIST[stock['stock_code']]['MAX_BUY_PRICE']))
|
||||
|
||||
LAST_DATA = hts.getLastData(stock['stock_code'], today)
|
||||
result_m1 = hts.getRealTime(stock['stock_code'], today, LAST_DATA)
|
||||
result_tic_m1 = hts.makeTickData1(result_m1, mins=1)
|
||||
data = hts.analyze(result_tic_m1)
|
||||
result_tic_m30 = hts.makeTickData2(result_tic_m1, mins=30)
|
||||
data_signal = hts.analyze(result_tic_m30)
|
||||
# data.drop(data.index[:len(data) - analyzed_day], inplace=True)
|
||||
|
||||
hts.buyRealTime(stock, data, data_signal, BUY_LIST[stock['stock_code']]['MAX_BUY_PRICE'], BUY_LIST[stock['stock_code']]['BUY_LIST_1'])
|
||||
close_data[stock['stock_code']] = data['close'][-1]
|
||||
|
||||
if INIT:
|
||||
hts.bot.sendMsg("Alive... close: {}".format(str(close_data)))
|
||||
INIT = False
|
||||
|
||||
if int(THIS_TIME.strftime("%M")) % 50 == 0:
|
||||
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(60)
|
||||
|
||||
db_filename = os.path.join(RESOURCE_PATH, "hts.db")
|
||||
for stock in stocks:
|
||||
hts.insertStockData(today, stock['stock_code'], stock['stock_name'])
|
||||
hts.disconnect()
|
||||
|
||||
hts.bot.sendMsg("done...")
|
||||
print("done...")
|
||||
400
HTS_etf_long.py
400
HTS_etf_long.py
@@ -1,400 +0,0 @@
|
||||
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 stock_code == "^KS11":
|
||||
if slow_k < 20: type_stock['day'] = 10
|
||||
if 20 < slow_k < 25: type_stock['day'] = 7.5
|
||||
if 25 < slow_k < 30: type_stock['day'] = 5
|
||||
if 30 < slow_k < 35: type_stock['day'] = 2.5
|
||||
|
||||
if slow_k_week < 20: type_stock['week'] = 100
|
||||
if 20 < slow_k_week < 25: type_stock['week'] = 75
|
||||
if 25 < slow_k_week < 30: type_stock['week'] = 50
|
||||
if 30 < slow_k_week < 35: type_stock['week'] = 25
|
||||
|
||||
if slow_k_month < 20: type_stock['month'] = 1000
|
||||
if 20 < slow_k_month < 25: type_stock['month'] = 750
|
||||
if 25 < slow_k_month < 30: type_stock['month'] = 500
|
||||
if 30 < slow_k_month < 35: type_stock['month'] = 250
|
||||
else:
|
||||
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
|
||||
|
||||
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=False)
|
||||
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": "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...")
|
||||
358
HTS_etf_short.py
358
HTS_etf_short.py
@@ -1,358 +0,0 @@
|
||||
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...")
|
||||
181
HTS_stocks.py
181
HTS_stocks.py
@@ -1,181 +0,0 @@
|
||||
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 30.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()
|
||||
|
||||
while datetime.strptime(today + " 070000", '%Y%m%d %H%M%S') < THIS_TIME < datetime.strptime(today + " 153100", '%Y%m%d %H%M%S'):
|
||||
THIS_TIME = datetime.now()
|
||||
|
||||
# 1515 까지만 매수를 시도한다.
|
||||
if datetime.strptime(today + " 090500", '%Y%m%d %H%M%S') < THIS_TIME < datetime.strptime(today + " 151500", '%Y%m%d %H%M%S'):
|
||||
|
||||
today_stock = self.get_today_stock()
|
||||
if len(today_stock) < 1:
|
||||
self.sellStocks()
|
||||
time.sleep(300)
|
||||
continue
|
||||
|
||||
for idx, stock in enumerate(today_stock):
|
||||
stock_code = stock['code']
|
||||
filename = stock['filename']
|
||||
|
||||
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))
|
||||
|
||||
arr = os.path.splitext(filename)
|
||||
os.rename(filename, arr[0]+'.[BUY]'+arr[1])
|
||||
|
||||
# 로그 출력
|
||||
print("BUY", THIS_TIME.strftime('%Y%m%d %H%M%S'), orderNum, stock_code, '', bs_buy_price, buy_count)
|
||||
|
||||
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... mem: {:.1f}".format(vm_item['idle']))
|
||||
|
||||
time.sleep(100)
|
||||
|
||||
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 = []
|
||||
path = os.path.join(self.RESOURCE_PATH, 'analysis', '종목선택')
|
||||
file_list = os.listdir(path)
|
||||
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"):
|
||||
stock = {'code': info.group(2), 'filename': os.path.join(path, filename)}
|
||||
today_stock.append(stock)
|
||||
|
||||
return 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...")
|
||||
274
JSDPattern.py
Normal file
274
JSDPattern.py
Normal file
@@ -0,0 +1,274 @@
|
||||
# https://bibot.tistory.com/63
|
||||
# https://nonmeyet.tistory.com/entry/Python-TALib%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-%EB%B9%84%ED%8A%B8%EC%BD%94%EC%9D%B8%EC%A3%BC%EA%B0%80%EA%B8%B0%EC%88%A0%EB%B6%84%EC%84%9D-%EB%B3%B4%EC%A1%B0%EC%A7%80%ED%91%9C-%EC%B6%94%EA%B0%80
|
||||
# https://lunadaddy.tistory.com/122
|
||||
# https://wikidocs.net/186885
|
||||
|
||||
import os
|
||||
import numpy as np
|
||||
np.seterr(divide='ignore', invalid='ignore')
|
||||
import pyupbit
|
||||
import math
|
||||
import sqlite3
|
||||
# https://www.lfd.uci.edu/~gohlke/pythonlibs/#ta-lib
|
||||
# https://lunadaddy.tistory.com/122
|
||||
import talib
|
||||
import pandas as pd
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from stock.analysis.IchimokuCloud import IchimokuCloud
|
||||
|
||||
class JSDPattern:
|
||||
RESOURCE_PATH = None
|
||||
ichimokuCloud = None
|
||||
scaler = None
|
||||
|
||||
def __init__(self, RESOURCE_PATH=None):
|
||||
if RESOURCE_PATH is None:
|
||||
self.RESOURCE_PATH = os.path.join(os.getcwd(), "resources")
|
||||
else:
|
||||
self.RESOURCE_PATH = RESOURCE_PATH
|
||||
|
||||
self.ichimokuCloud = IchimokuCloud()
|
||||
return
|
||||
|
||||
def makeTickData(self, data, mins=1):
|
||||
result = {
|
||||
"ymd": [],
|
||||
"open": [], "close": [], "high": [], "low": [], "volume": [], "volume_up": [], "volume_down": [], "volume_updown_diff": []
|
||||
}
|
||||
|
||||
for i in range(mins, len(data['ymd'])+1, mins):
|
||||
result["ymd"].append(data['ymd'][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["volume"].append(data['volume'][i-1])
|
||||
|
||||
if data['open'][i-1] < data['close'][i-1]:
|
||||
result["volume_up"].append(data['volume'][i-1])
|
||||
result["volume_down"].append(0)
|
||||
elif data['close'][i-1] < data['open'][i-1]:
|
||||
result["volume_down"].append(-1*data['volume'][i-1])
|
||||
result["volume_up"].append(0)
|
||||
else:
|
||||
result["volume_up"].append(0)
|
||||
result["volume_down"].append(0)
|
||||
|
||||
up = [data['volume'][i - mins + c] for c in range(len(data['volume'][i - mins: i])) if data['close'][i - mins + c] < data['open'][i - mins + c]]
|
||||
down = [data['volume'][i - mins + c] for c in range(len(data['volume'][i - mins: i])) if data['close'][i - mins + c] < data['open'][i - mins + c]]
|
||||
result["volume_updown_diff"].append(sum(up) - sum(down))
|
||||
|
||||
return result
|
||||
|
||||
def append(self, df=None, result=None):
|
||||
data = {
|
||||
"ymd": [],
|
||||
"open": [], "close": [], "high": [], "low": [], "volume": []
|
||||
}
|
||||
|
||||
if result is not None:
|
||||
for i in range(len(result['ymd'])):
|
||||
data['ymd'].append(result['ymd'][i])
|
||||
data['open'].append(result['open'][i])
|
||||
data['close'].append(result['close'][i])
|
||||
data['high'].append(result['high'][i])
|
||||
data['low'].append(result['low'][i])
|
||||
data['volume'].append(result['volume'][i])
|
||||
|
||||
if df is not None:
|
||||
for i in range(len(df)):
|
||||
data['ymd'].append(df.index[i])
|
||||
data['open'].append(df['open'].iloc[i])
|
||||
data['close'].append(df['close'].iloc[i])
|
||||
data['high'].append(df['high'].iloc[i])
|
||||
data['low'].append(df['low'].iloc[i])
|
||||
data['volume'].append(df['volume'].iloc[i])
|
||||
|
||||
return data
|
||||
|
||||
def getDBData(self, stock_code, day, mins, get_days=14):
|
||||
|
||||
if mins == 3:
|
||||
table = 'minute3'
|
||||
elif mins == 5:
|
||||
table = 'minute5'
|
||||
elif mins == 10:
|
||||
table = 'minute10'
|
||||
elif mins == 20:
|
||||
table = 'minute20'
|
||||
elif mins == 30:
|
||||
table = 'minute30'
|
||||
elif mins == 60:
|
||||
table = 'minute60'
|
||||
elif mins == 200:
|
||||
table = 'minute200'
|
||||
elif mins == 1440:
|
||||
table = 'daily'
|
||||
else:
|
||||
table = 'minutely'
|
||||
|
||||
conn = sqlite3.connect(os.path.join(self.RESOURCE_PATH, 'coins.db'))
|
||||
cursor = conn.cursor()
|
||||
|
||||
result = {"ymd": [], "open": [], "close": [], "high": [], "low": [], "volume": [], "label": []}
|
||||
for i in range(get_days, -1, -1):
|
||||
this_day = (datetime.strptime(day, '%Y%m%d') - timedelta(i)).strftime('%Y%m%d')
|
||||
cursor.execute('SELECT ymd, hms, open, high, low, close, volume FROM ' + table + ' WHERE (CODE=? or CODE=?) and (ymd=?) order by ymd, hms', (stock_code, stock_code.replace('KRW-', ''), this_day,))
|
||||
|
||||
db_result = cursor.fetchall()
|
||||
for rows in db_result:
|
||||
ymd = rows[0] # hts.날짜
|
||||
hms = rows[1] # hts.시간
|
||||
open = rows[2] # hts.시가
|
||||
high = rows[3] # hts.고가
|
||||
low = rows[4] # hts.저가
|
||||
close = rows[5] # hts.종가
|
||||
vol = rows[6] # hts.거래량
|
||||
|
||||
temp = datetime.strptime(str(ymd) + " " + hms, '%Y%m%d %H%M%S')
|
||||
|
||||
result["ymd"].append(temp)
|
||||
result["open"].append(float(open))
|
||||
result["close"].append(float(close))
|
||||
result["high"].append(float(high))
|
||||
result["low"].append(float(low))
|
||||
result["volume"].append(float(vol))
|
||||
|
||||
cursor.close()
|
||||
conn.close()
|
||||
|
||||
return result
|
||||
|
||||
def getCoinData(self, ticker, mins=None, to=None, ymd=None, get_days=14):
|
||||
result = None
|
||||
|
||||
if ymd is not None and datetime.now() < datetime.strptime(ymd, '%Y%m%d'):
|
||||
ymd = None
|
||||
|
||||
if ymd is None:
|
||||
if to is None:
|
||||
if mins is None:
|
||||
df = pyupbit.get_ohlcv(ticker=ticker['ticker_code'])
|
||||
else:
|
||||
if mins == 1440:
|
||||
df = pyupbit.get_ohlcv(ticker=ticker['ticker_code'], interval='minute1', count=1)
|
||||
else:
|
||||
df = pyupbit.get_ohlcv(ticker=ticker['ticker_code'], interval='minute' + str(mins))
|
||||
else:
|
||||
df = pyupbit.get_ohlcv(ticker=ticker['ticker_code'], interval='minute' + str(mins), to=to)
|
||||
|
||||
if df is not None:
|
||||
df["datetime"] = df.index
|
||||
df = df[['open', 'high', 'low', 'close', 'volume']].astype(float)
|
||||
|
||||
if mins is not None:
|
||||
result = self.getDBData(ticker['ticker_code'], datetime.today().strftime('%Y%m%d'), mins=mins, get_days=get_days)
|
||||
|
||||
data = self.append(df, result)
|
||||
|
||||
else:
|
||||
result = self.getDBData(ticker['ticker_code'], ymd, mins=mins, get_days=get_days)
|
||||
data = self.append(df=None, result=result)
|
||||
|
||||
return data
|
||||
|
||||
def is_Support(self, low, i, observation_time=5):
|
||||
# https://sine-qua-none.tistory.com/198
|
||||
|
||||
# c1 = df.Low[i] < df.Low[i - 1] < df.Low[i - 2] < df.Low[i - 3]
|
||||
# c2 = df.Low[i] < df.Low[i + 1] < df.Low[i + 2] < df.Low[i + 3]
|
||||
# return c1 & c2
|
||||
|
||||
#if low[i] == np.min(low[i - 2*self.observation_time:i + 1]):
|
||||
if low[i] == np.min(low[i - observation_time:i + observation_time + 1]):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def is_Resistance(self, high, i, observation_time=5):
|
||||
# https://sine-qua-none.tistory.com/198
|
||||
|
||||
# c1 = df.High[i] > df.High[i - 1] > df.High[i - 2] > df.High[i - 3]
|
||||
# c2 = df.High[i] > df.High[i + 1] > df.High[i + 2] > df.High[i + 3]
|
||||
# return c1 & c2
|
||||
# if df['high'][i] == np.max(df['high'][i - self.observation_time:i + self.observation_time + 1]):
|
||||
#if high[i] == np.max(high[i - 2*self.observation_time:i + 1]):
|
||||
if high[i] == np.max(high[i - observation_time:i + observation_time + 1]):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def getDiff_Rate(self, price1, price2, duration=1440, move=None):
|
||||
# price1: close, price2: laggingSpan_27
|
||||
diff = [0 for i in range(len(price1))]
|
||||
diff_rate = [0 for i in range(len(price1))]
|
||||
|
||||
for i in range(0, len(price1)):
|
||||
if price1[i] is not None and not math.isnan(price1[i]) and price2[i] is not None and not math.isnan(price2[i]):
|
||||
diff[i] = price1[i] - price2[i]
|
||||
else:
|
||||
diff[i] = np.nan
|
||||
|
||||
if len(price1) < duration:
|
||||
duration = 52
|
||||
|
||||
for i in range(0, len(price1)):
|
||||
|
||||
if duration <= i:
|
||||
l = [d for d in diff[i - duration:i + 1] if d is not None and 0 < d]
|
||||
if 0 < len(l):
|
||||
min_v_p = np.min(l)
|
||||
else:
|
||||
min_v_p = 0
|
||||
l = [d for d in diff[i - duration:i + 1] if d is not None and 0 < d]
|
||||
if 0 < len(l):
|
||||
max_v_p = np.max(l)
|
||||
else:
|
||||
max_v_p = 0
|
||||
l = [d for d in diff[i - duration:i + 1] if d is not None and d < 0]
|
||||
if 0 < len(l):
|
||||
min_v_m = np.min(l)
|
||||
else:
|
||||
min_v_m = 0
|
||||
l = [d for d in diff[i - duration:i + 1] if d is not None and d < 0]
|
||||
if 0 < len(l):
|
||||
max_v_m = np.max(l)
|
||||
else:
|
||||
max_v_m = 0
|
||||
|
||||
if diff[i] is not None and not math.isnan(diff[i]):
|
||||
if 0 <= diff[i]:
|
||||
if max_v_p - min_v_p == 0:
|
||||
diff_rate[i] = 0
|
||||
else:
|
||||
diff_rate[i] = (diff[i] - min_v_p) / (max_v_p - min_v_p)
|
||||
else:
|
||||
if max_v_m - min_v_m == 0:
|
||||
diff_rate[i] = 0
|
||||
else:
|
||||
diff_rate[i] = ((diff[i] - min_v_m) / (max_v_m - min_v_m)) - 1
|
||||
else:
|
||||
diff_rate[i] = np.nan
|
||||
|
||||
return diff, diff_rate
|
||||
|
||||
|
||||
def getDisparity_low_min(self, ticker, min='minutely'):
|
||||
try:
|
||||
self.conn = sqlite3.connect(os.path.join(self.RESOURCE_PATH, "coins.db"))
|
||||
self.cursor = self.conn.cursor()
|
||||
|
||||
self.cursor.execute("SELECT lowest_disparity FROM disparity WHERE (CODE=? or CODE=?) AND TYPE=?", (ticker['ticker_code'], ticker['ticker_code'].replace('KRW-', ''), min))
|
||||
db_result = self.cursor.fetchall()
|
||||
self.cursor.close()
|
||||
self.conn.close()
|
||||
|
||||
if 0 < len(db_result):
|
||||
return db_result[0][0]
|
||||
|
||||
except:
|
||||
return 0.90
|
||||
return 0.90
|
||||
769
JSDPattern_daily.py
Normal file
769
JSDPattern_daily.py
Normal file
@@ -0,0 +1,769 @@
|
||||
# https://bibot.tistory.com/63
|
||||
# https://nonmeyet.tistory.com/entry/Python-TALib%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-%EB%B9%84%ED%8A%B8%EC%BD%94%EC%9D%B8%EC%A3%BC%EA%B0%80%EA%B8%B0%EC%88%A0%EB%B6%84%EC%84%9D-%EB%B3%B4%EC%A1%B0%EC%A7%80%ED%91%9C-%EC%B6%94%EA%B0%80
|
||||
# https://lunadaddy.tistory.com/122
|
||||
# https://wikidocs.net/186885
|
||||
|
||||
import numpy as np
|
||||
from scipy.signal import argrelextrema
|
||||
np.seterr(divide='ignore', invalid='ignore')
|
||||
# https://www.lfd.uci.edu/~gohlke/pythonlibs/#ta-lib
|
||||
# https://lunadaddy.tistory.com/122
|
||||
import talib
|
||||
import pandas as pd
|
||||
from datetime import datetime, timedelta
|
||||
from sklearn.preprocessing import MinMaxScaler
|
||||
|
||||
from JSDPattern import JSDPattern
|
||||
|
||||
|
||||
class JSDPattern_daily(JSDPattern):
|
||||
scaler = None
|
||||
|
||||
def __init__(self, RESOURCE_PATH=None):
|
||||
super().__init__(RESOURCE_PATH)
|
||||
self.scaler = MinMaxScaler()
|
||||
return
|
||||
|
||||
def get_Support_Resistance(self, df):
|
||||
n = 5
|
||||
min_price = df.iloc[argrelextrema(df.values, np.less_equal, order=n)[0]]
|
||||
max_price = df.iloc[argrelextrema(df.values, np.greater_equal, order=n)[0]]
|
||||
return min_price.iloc[-1], max_price.iloc[-1]
|
||||
|
||||
def analyze_raw(self, result, mins=1440):
|
||||
result["volume"] = [result["volume"][i] if 0 < result["volume"][i] else 1 for i in range(len(result["volume"]))]
|
||||
# 기본 캔들 정보
|
||||
open_df = pd.DataFrame(result["open"])
|
||||
close_df = pd.DataFrame(result["close"])
|
||||
high_df = pd.DataFrame(result["high"])
|
||||
low_df = pd.DataFrame(result["low"])
|
||||
volume_df = pd.DataFrame(result["volume"])
|
||||
|
||||
# 중복 제거
|
||||
ymd_df = pd.DataFrame(result["ymd"])
|
||||
data_dup = pd.concat([ymd_df, open_df, close_df, high_df, low_df, volume_df], axis=1)
|
||||
data_dup.columns = ["ymd", "open", "close", "high", "low", "volume"]
|
||||
data_dup.index = pd.DatetimeIndex(result["ymd"])
|
||||
data_dup_sorted = data_dup.sort_index(ascending=True)
|
||||
data_dup_sorted = data_dup_sorted.drop_duplicates()
|
||||
|
||||
ymd_df = data_dup_sorted["ymd"]
|
||||
open_df = data_dup_sorted["open"]
|
||||
close_df = data_dup_sorted["close"]
|
||||
high_df = data_dup_sorted["high"]
|
||||
low_df = data_dup_sorted["low"]
|
||||
volume_df = data_dup_sorted["volume"]
|
||||
|
||||
min_price_list = [None for i in range(len(close_df)+51)]
|
||||
max_price_list = [None for i in range(len(close_df)+51)]
|
||||
for i in range(len(close_df)):
|
||||
if 480 < i:
|
||||
min_price_list[i], max_price_list[i] = self.get_Support_Resistance(close_df[i-120:i+1])
|
||||
|
||||
ymd = ymd_df.tolist()
|
||||
open = open_df.tolist()
|
||||
close = close_df.tolist()
|
||||
high = high_df.tolist()
|
||||
low = low_df.tolist()
|
||||
volume = volume_df.tolist()
|
||||
|
||||
# ichimokuCloud
|
||||
df = pd.concat([ymd_df, open_df, close_df, high_df, low_df, volume_df], axis=1)
|
||||
column_names = ['DATE', 'open', 'close', 'high', 'low', 'volume']
|
||||
df.columns = column_names
|
||||
c, b, l, s = 9, 26, 52, 26
|
||||
# 1. 전환선 = (과거 9일 동안 최고가 + 최저가) / 2
|
||||
# 당일을 포함한 9일 동안의 최고가와 최저가의 중간 값을 평균으로 나타낸다.
|
||||
changeLine = (df.high.rolling(c).max() + df.low.rolling(c).min()) / 2
|
||||
# 2. 기준선 = 과거 26일 동안 최고가 + 최저가) / 2
|
||||
# 당일을 포함한 26일 동안의 최고가와 최저가의 중간 값을 평균으로 나타낸다.
|
||||
baseLine = (df.high.rolling(b).max() + df.low.rolling(b).min()) / 2
|
||||
|
||||
# 3. 후행스팬 = 현재 close가격의 26일전 반영
|
||||
laggingSpan = [df.close.values[i + s] for i in range(len(df.close) - s)]
|
||||
laggingSpan += [None for i in range(s)]
|
||||
laggingSpan = np.array(laggingSpan)
|
||||
|
||||
# 4. 선행스팬 1 = ((기준선 + 전환선) / 2)를 26일 선행하여 배치
|
||||
# 전환선과 기준선의 평균값을 구해 당일 포함 26일 앞으로 이동시킨 선 (중-단기 구간의 힘을 보여줌)
|
||||
tmp_leadingSpan1 = (changeLine + baseLine) / 2
|
||||
""" S: 26일 선행시킴 """
|
||||
leadingSpan1 = list(tmp_leadingSpan1.values)
|
||||
for i in range(b - 1):
|
||||
leadingSpan1.insert(0, None)
|
||||
""" E: 26일 선행시킴 """
|
||||
|
||||
# 5. 선행스팬 2 = ((최근 52일 동안 최고가 + 최저가) / 2)를 26일 선행하여 배치
|
||||
# 당일을 포함한 52일 동안의 최고가와 최저가의 평균을 26일 앞으로 이동시킨 선 (장기으로 형성된 선이기 때문에 가장 느리게 변함)
|
||||
tmp_leadingSpan2 = (df.high.rolling(l).max() + df.low.rolling(l).min()) / 2
|
||||
""" S: 52일 선행시킴 """
|
||||
leadingSpan2 = list(tmp_leadingSpan2.values)
|
||||
for i in range(l - 1):
|
||||
leadingSpan2.insert(0, None)
|
||||
""" S: 52일 선행시킴 """
|
||||
|
||||
baseLine = baseLine.tolist()
|
||||
changeLine = changeLine.tolist()
|
||||
laggingSpan = list(laggingSpan)
|
||||
current_index = len(ymd)
|
||||
|
||||
for i in range(51):
|
||||
if len(ymd) < len(leadingSpan2):
|
||||
if mins == 1440:
|
||||
ymd.append(ymd[-1] + timedelta(days=1))
|
||||
else:
|
||||
ymd.append(ymd[-1] + timedelta(minutes=1))
|
||||
if len(open) < len(leadingSpan2):
|
||||
open.append(None)
|
||||
if len(close) < len(leadingSpan2):
|
||||
close.append(None)
|
||||
if len(high) < len(leadingSpan2):
|
||||
high.append(None)
|
||||
if len(low) < len(leadingSpan2):
|
||||
low.append(None)
|
||||
if len(volume) < len(leadingSpan2):
|
||||
volume.append(None)
|
||||
if len(baseLine) < len(leadingSpan2):
|
||||
baseLine.append(None)
|
||||
if len(changeLine) < len(leadingSpan2):
|
||||
changeLine.append(None)
|
||||
if len(laggingSpan) < len(leadingSpan2):
|
||||
laggingSpan.append(None)
|
||||
for i in range(26):
|
||||
if len(leadingSpan1) < len(leadingSpan2):
|
||||
leadingSpan1.append(leadingSpan1[-1])
|
||||
|
||||
# 7일 신고가
|
||||
new_high_7 = [0 for c in range(6)] + [1 if (changeLine[c - 1] is not None and changeLine[c] is not None and changeLine[c - 1] < changeLine[c]) and None not in close[c - 6:c + 1] and max(close[c - 6:c]) < close[c] else 0 for c in range(6, len(close))]
|
||||
# 9일 신고가
|
||||
new_high_9 = [0 for c in range(8)] + [1 if (changeLine[c - 1] is not None and changeLine[c] is not None and changeLine[c - 1] < changeLine[c]) and None not in close[c - 8:c + 1] and max(close[c - 8:c]) < close[c] else 0 for c in range(8, len(close))]
|
||||
# 26일 신고가
|
||||
new_high_26 = [0 for c in range(25)] + [1 if (baseLine[c - 1] is not None and baseLine[c] is not None and baseLine[c - 1] < baseLine[c]) and None not in close[c - 8:c + 1] and max(close[c - 25:c]) < close[c] else 0 for c in range(25, len(close))]
|
||||
# 33일 신고가
|
||||
new_high_33 = [0 for c in range(32)] + [1 if (leadingSpan1[c - 1] is not None and leadingSpan1[c] is not None and leadingSpan1[c - 1] < leadingSpan1[c]) and None not in close[c - 8:c + 1] and max(close[c - 32:c]) < close[c] else 0 for c in range(32, len(close))]
|
||||
# 52일 신고가
|
||||
new_high_52 = [0 for c in range(51)] + [1 if (leadingSpan2[c - 1] is not None and leadingSpan2[c] is not None and leadingSpan2[c - 1] < leadingSpan2[c]) and None not in close[c - 8:c + 1] and max(close[c - 51:c]) < close[c] else 0 for c in range(51, len(close))]
|
||||
|
||||
# 7일 신저가
|
||||
new_low_7 = [0 for c in range(6)] + [1 if (changeLine[c - 1] is not None and changeLine[c] is not None and changeLine[c - 1] < changeLine[c]) and None not in close[c - 6:c + 1] and close[c - 7] < min(close[c - 6:c + 1]) else 0 for c in range(6, len(close))]
|
||||
# 9일 신저가
|
||||
new_low_9 = [0 for c in range(8)] + [1 if (changeLine[c - 1] is not None and changeLine[c] is not None and changeLine[c - 1] < changeLine[c]) and None not in close[c - 8:c + 1] and close[c - 9] < min(close[c - 8:c + 1]) else 0 for c in range(8, len(close))]
|
||||
# 26일 신저가
|
||||
new_low_26 = [0 for c in range(25)] + [1 if (baseLine[c - 1] is not None and baseLine[c] is not None and baseLine[c - 1] < baseLine[c]) and None not in close[c - 8:c + 1] and close[c - 26] < min(close[c - 25:c + 1]) else 0 for c in range(25, len(close))]
|
||||
# 33일 신저가
|
||||
new_low_33 = [0 for c in range(32)] + [1 if (leadingSpan1[c - 1] is not None and leadingSpan1[c] is not None and leadingSpan1[c - 1] < leadingSpan1[c]) and None not in close[c - 8:c + 1] and close[c - 33] < min(close[c - 32:c + 1]) else 0 for c in range(32, len(close))]
|
||||
# 52일 신저가
|
||||
new_low_52 = [0 for c in range(51)] + [1 if (leadingSpan2[c - 1] is not None and leadingSpan2[c] is not None and leadingSpan2[c - 1] < leadingSpan2[c]) and None not in close[c - 8:c + 1] and close[c - 52] < min(close[c - 51:c + 1]) else 0 for c in range(51, len(close))]
|
||||
|
||||
# 이동 평균
|
||||
close_df = pd.DataFrame(close)
|
||||
avg5 = list(np.reshape(close_df.ewm(5).mean().values, -1))
|
||||
avg10 = list(np.reshape(close_df.ewm(10).mean().values, -1))
|
||||
avg20 = list(np.reshape(close_df.ewm(20).mean().values, -1))
|
||||
avg60 = list(np.reshape(close_df.ewm(60).mean().values, -1))
|
||||
avg90 = list(np.reshape(close_df.ewm(90).mean().values, -1))
|
||||
avg120 = list(np.reshape(close_df.ewm(120).mean().values, -1))
|
||||
avg240 = list(np.reshape(close_df.ewm(240).mean().values, -1))
|
||||
avg360 = list(np.reshape(close_df.ewm(360).mean().values, -1))
|
||||
avg480 = list(np.reshape(close_df.ewm(480).mean().values, -1))
|
||||
avg720 = list(np.reshape(close_df.ewm(720).mean().values, -1))
|
||||
avg1440 = list(np.reshape(close_df.ewm(1440).mean().values, -1))
|
||||
avg2880 = list(np.reshape(close_df.ewm(2880).mean().values, -1))
|
||||
|
||||
# 이격도
|
||||
disparity_avg5_df = (close_df / close_df.ewm(span=5, min_periods=5, adjust=False).mean())
|
||||
disparity_avg10_df = (close_df / close_df.ewm(span=10, min_periods=10, adjust=False).mean())
|
||||
disparity_avg20_df = (close_df / close_df.ewm(span=20, min_periods=20, adjust=False).mean())
|
||||
disparity_avg60_df = (close_df / close_df.ewm(span=60, min_periods=60, adjust=False).mean())
|
||||
disparity_avg120_df = (close_df / close_df.ewm(span=120, min_periods=120, adjust=False).mean())
|
||||
disparity_avg240_df = (close_df / close_df.ewm(span=240, min_periods=240, adjust=False).mean())
|
||||
disparity_avg480_df = (close_df / close_df.ewm(span=480, min_periods=480, adjust=False).mean())
|
||||
disparity_avg720_df = (close_df / close_df.ewm(span=720, min_periods=720, adjust=False).mean())
|
||||
disparity_avg1440_df = (close_df / close_df.ewm(span=1440, min_periods=1440, adjust=False).mean())
|
||||
|
||||
disparity_480_loc = [0 for i in range(len(close))]
|
||||
disparity_1440_loc = [0 for i in range(len(close))]
|
||||
disparity_avg480_list = list(disparity_avg480_df.values.reshape(-1))
|
||||
disparity_avg1440_list = list(disparity_avg1440_df.values.reshape(-1))
|
||||
for i in range(0, len(close)):
|
||||
if 2880 < i:
|
||||
l = [d for d in disparity_avg480_list[i - 1440:i + 1]]
|
||||
min_v = np.min(l)
|
||||
max_v = np.max(l)
|
||||
disparity_480_loc[i] = (disparity_avg480_list[i] - min_v) / (max_v - min_v)
|
||||
l = [d for d in disparity_avg1440_list[i - 1440:i + 1]]
|
||||
min_v = np.min(l)
|
||||
max_v = np.max(l)
|
||||
disparity_1440_loc[i] = (disparity_avg1440_list[i] - min_v) / (max_v - min_v)
|
||||
|
||||
disparity_480_loc_df = pd.DataFrame(disparity_480_loc)
|
||||
disparity_1440_loc_df = pd.DataFrame(disparity_1440_loc)
|
||||
|
||||
np_high, np_low, np_close = np.array(high, dtype=np.float64), np.array(low, dtype=np.float64), np.array(close, dtype=np.float64)
|
||||
slowk_5_df, slowd_5_df = talib.STOCH(np_high, np_low, np_close, fastk_period=5, slowk_period=3, slowk_matype=0, slowd_period=3, slowd_matype=0)
|
||||
slowk_10_df, slowd_10_df = talib.STOCH(np_high, np_low, np_close, fastk_period=10, slowk_period=6, slowk_matype=0, slowd_period=6, slowd_matype=0)
|
||||
slowk_20_df, slowd_20_df = talib.STOCH(np_high, np_low, np_close, fastk_period=20, slowk_period=12, slowk_matype=0, slowd_period=12, slowd_matype=0)
|
||||
slowk_60_df, slowd_60_df = talib.STOCH(np_high, np_low, np_close, fastk_period=60, slowk_period=37, slowk_matype=0, slowd_period=37, slowd_matype=0)
|
||||
slowk_120_df, slowd_120_df = talib.STOCH(np_high, np_low, np_close, fastk_period=120, slowk_period=74, slowk_matype=0, slowd_period=74, slowd_matype=0)
|
||||
slowk_240_df, slowd_240_df = talib.STOCH(np_high, np_low, np_close, fastk_period=240, slowk_period=148, slowk_matype=0, slowd_period=148, slowd_matype=0)
|
||||
slowk_480_df, slowd_480_df = talib.STOCH(np_high, np_low, np_close, fastk_period=480, slowk_period=296, slowk_matype=0, slowd_period=296, slowd_matype=0)
|
||||
|
||||
# 최고/최저 위치
|
||||
loc_240 = [None for i in range(len(close))]
|
||||
for i in range(240, len(close)):
|
||||
min_v = np.min(result["close"][i - 239:i + 1])
|
||||
max_v = np.max(result["close"][i - 239:i + 1])
|
||||
if close[i] is not None:
|
||||
loc_240[i] = ((close[i] - min_v) / (max_v - min_v))
|
||||
else:
|
||||
loc_240[i] = None
|
||||
|
||||
loc_240 = pd.DataFrame(loc_240)
|
||||
loc_240_k = loc_240.to_numpy().reshape(-1)
|
||||
loc_240_d = loc_240.rolling(20).mean()
|
||||
loc_240_s = loc_240.rolling(60).mean()
|
||||
loc_240_d = loc_240_d.to_numpy().reshape(-1)
|
||||
loc_240_s = loc_240_s.to_numpy().reshape(-1)
|
||||
|
||||
n, t = 20, 2
|
||||
max_20 = close_df.rolling(window=n).mean()
|
||||
stddev_20 = close_df.rolling(window=n).std()
|
||||
upper_20 = max_20 + (stddev_20 * t) # 상단 볼리저 밴드
|
||||
lower_20 = max_20 - (stddev_20 * t) # 하단 볼리저 밴드
|
||||
middle_20 = (upper_20 + lower_20) / 2
|
||||
|
||||
width_df = (upper_20 - lower_20) / middle_20
|
||||
width_min = np.min(width_df[0])
|
||||
width_max = np.max(width_df[0])
|
||||
bb_width_df = 100 * (width_df - width_min) / (width_max - width_min)
|
||||
bb_pb_df = 100 * (close_df - lower_20) / (upper_20 - lower_20)
|
||||
|
||||
upper_20 = list(np.reshape(upper_20.values, -1))
|
||||
lower_20 = list(np.reshape(lower_20.values, -1))
|
||||
middle_20 = list(np.reshape(middle_20.values, -1))
|
||||
|
||||
disparity_avg5_list = list(disparity_avg5_df.values.reshape(-1))
|
||||
disparity_avg20_list = list(disparity_avg20_df.values.reshape(-1))
|
||||
disparity_avg60_list = list(disparity_avg60_df.values.reshape(-1))
|
||||
disparity_avg120_list = list(disparity_avg120_df.values.reshape(-1))
|
||||
disparity_avg240_list = list(disparity_avg240_df.values.reshape(-1))
|
||||
disparity_avg480_list = list(disparity_avg480_df.values.reshape(-1))
|
||||
disparity_avg720_list = list(disparity_avg720_df.values.reshape(-1))
|
||||
disparity_avg1440_list = list(disparity_avg1440_df.values.reshape(-1))
|
||||
|
||||
disparity_diff_20_5, disparity_diff_20_5_rate = self.getDiff_Rate(disparity_avg20_list, disparity_avg5_list, duration=20)
|
||||
disparity_diff_60_20, disparity_diff_60_20_rate = self.getDiff_Rate(disparity_avg60_list, disparity_avg5_list, duration=60)
|
||||
disparity_diff_120_20, disparity_diff_120_20_rate = self.getDiff_Rate(disparity_avg120_list, disparity_avg5_list, duration=120)
|
||||
disparity_diff_240_20, disparity_diff_240_20_rate = self.getDiff_Rate(disparity_avg240_list, disparity_avg5_list, duration=240)
|
||||
disparity_diff_480_20, disparity_diff_480_20_rate = self.getDiff_Rate(disparity_avg480_list, disparity_avg5_list, duration=480)
|
||||
disparity_diff_720_20, disparity_diff_720_20_rate = self.getDiff_Rate(disparity_avg720_list, disparity_avg5_list, duration=720)
|
||||
disparity_diff_1440_20, disparity_diff_1440_20_rate = self.getDiff_Rate(disparity_avg1440_list, disparity_avg5_list, duration=1440)
|
||||
|
||||
df_list = [
|
||||
pd.DataFrame(ymd),
|
||||
pd.DataFrame(open), pd.DataFrame(close), pd.DataFrame(high), pd.DataFrame(low), pd.DataFrame(volume),
|
||||
pd.DataFrame(changeLine), pd.DataFrame(baseLine), pd.DataFrame(laggingSpan), pd.DataFrame(leadingSpan1), pd.DataFrame(leadingSpan2),
|
||||
|
||||
pd.DataFrame(disparity_diff_20_5), pd.DataFrame(disparity_diff_20_5_rate),
|
||||
pd.DataFrame(disparity_diff_60_20), pd.DataFrame(disparity_diff_60_20_rate),
|
||||
pd.DataFrame(disparity_diff_120_20), pd.DataFrame(disparity_diff_120_20_rate),
|
||||
pd.DataFrame(disparity_diff_240_20), pd.DataFrame(disparity_diff_240_20_rate),
|
||||
pd.DataFrame(disparity_diff_480_20), pd.DataFrame(disparity_diff_480_20_rate),
|
||||
pd.DataFrame(disparity_diff_720_20), pd.DataFrame(disparity_diff_720_20_rate),
|
||||
pd.DataFrame(disparity_diff_1440_20), pd.DataFrame(disparity_diff_1440_20_rate),
|
||||
|
||||
pd.DataFrame(loc_240_k), pd.DataFrame(loc_240_d), pd.DataFrame(loc_240_s),
|
||||
|
||||
pd.DataFrame(avg5), pd.DataFrame(avg10), pd.DataFrame(avg20), pd.DataFrame(avg60), pd.DataFrame(avg90), pd.DataFrame(avg120), pd.DataFrame(avg240), pd.DataFrame(avg360), pd.DataFrame(avg480), pd.DataFrame(avg720), pd.DataFrame(avg1440), pd.DataFrame(avg2880),
|
||||
disparity_avg5_df, disparity_avg10_df, disparity_avg20_df, disparity_avg60_df, disparity_avg120_df, disparity_avg240_df, disparity_avg480_df, disparity_avg720_df, disparity_avg1440_df, disparity_480_loc_df, disparity_1440_loc_df,
|
||||
|
||||
pd.DataFrame(upper_20), pd.DataFrame(lower_20), pd.DataFrame(middle_20),
|
||||
bb_width_df, bb_pb_df,
|
||||
|
||||
pd.DataFrame(new_high_7), pd.DataFrame(new_high_9), pd.DataFrame(new_high_26), pd.DataFrame(new_high_33), pd.DataFrame(new_high_52),
|
||||
pd.DataFrame(new_low_7), pd.DataFrame(new_low_9), pd.DataFrame(new_low_26), pd.DataFrame(new_low_33), pd.DataFrame(new_low_52),
|
||||
pd.DataFrame(slowk_5_df), pd.DataFrame(slowd_5_df),
|
||||
pd.DataFrame(slowk_10_df), pd.DataFrame(slowd_10_df),
|
||||
pd.DataFrame(slowk_20_df), pd.DataFrame(slowd_20_df),
|
||||
pd.DataFrame(slowk_60_df), pd.DataFrame(slowd_60_df),
|
||||
pd.DataFrame(slowk_120_df), pd.DataFrame(slowd_120_df),
|
||||
pd.DataFrame(slowk_240_df), pd.DataFrame(slowd_240_df),
|
||||
pd.DataFrame(slowk_480_df), pd.DataFrame(slowd_480_df),
|
||||
|
||||
pd.DataFrame(min_price_list), pd.DataFrame(max_price_list)
|
||||
]
|
||||
|
||||
data = pd.concat(df_list, axis=1)
|
||||
column_names = [
|
||||
'ymd',
|
||||
'open', 'close', 'high', 'low', 'volume',
|
||||
'changeLine', 'baseLine', 'laggingSpan', 'leadingSpan1', 'leadingSpan2',
|
||||
|
||||
'disparity_diff_20_5', 'disparity_diff_20_5_rate',
|
||||
'disparity_diff_60_20', 'disparity_diff_60_20_rate',
|
||||
'disparity_diff_120_20', 'disparity_diff_120_20_rate',
|
||||
'disparity_diff_240_20', 'disparity_diff_240_20_rate',
|
||||
'disparity_diff_480_20', 'disparity_diff_480_20_rate',
|
||||
'disparity_diff_720_20', 'disparity_diff_720_20_rate',
|
||||
'disparity_diff_1440_20', 'disparity_diff_1440_20_rate',
|
||||
|
||||
'loc_240_k', 'loc_240_d', 'loc_240_s',
|
||||
|
||||
'avg5', 'avg10', 'avg20', 'avg60', 'avg90', 'avg120', 'avg240', 'avg360', 'avg480', 'avg720', 'avg1440', 'avg2880',
|
||||
'disparity_avg5', 'disparity_avg10', 'disparity_avg20', 'disparity_avg60', 'disparity_avg120', 'disparity_avg240', 'disparity_avg480', 'disparity_avg720', 'disparity_avg1440', 'disparity_480_loc', 'disparity_1440_loc',
|
||||
|
||||
'upper_20', 'lower_20', 'middle_20',
|
||||
'bb_width', 'bb_pb',
|
||||
|
||||
'new_high_7', 'new_high_9', 'new_high_26', 'new_high_33', 'new_high_52',
|
||||
'new_low_7', 'new_low_9', 'new_low_26', 'new_low_33', 'new_low_52',
|
||||
|
||||
'slowk_5', 'slowd_5',
|
||||
'slowk_10', 'slowd_10',
|
||||
'slowk_20', 'slowd_20',
|
||||
'slowk_60', 'slowd_60',
|
||||
'slowk_120', 'slowd_120',
|
||||
'slowk_240', 'slowd_240',
|
||||
'slowk_480', 'slowd_480',
|
||||
|
||||
'min_price', 'max_price'
|
||||
]
|
||||
data.columns = column_names
|
||||
data.index = pd.DatetimeIndex(ymd)
|
||||
|
||||
return data, current_index
|
||||
|
||||
|
||||
def analyze_scale(self, result, mins=1440):
|
||||
result["volume"] = [result["volume"][i] if 0 < result["volume"][i] else 1 for i in range(len(result["volume"]))]
|
||||
# 기본 캔들 정보
|
||||
open_df = pd.DataFrame(result["open"])
|
||||
close_df = pd.DataFrame(result["close"])
|
||||
high_df = pd.DataFrame(result["high"])
|
||||
low_df = pd.DataFrame(result["low"])
|
||||
volume_df = pd.DataFrame(result["volume"])
|
||||
|
||||
# 중복 제거
|
||||
ymd_df = pd.DataFrame(result["ymd"])
|
||||
data_dup = pd.concat([ymd_df, open_df, close_df, high_df, low_df, volume_df], axis=1)
|
||||
data_dup.columns = ["ymd", "open", "close", "high", "low", "volume"]
|
||||
data_dup.index = pd.DatetimeIndex(result["ymd"])
|
||||
data_dup_sorted = data_dup.sort_index(ascending=True)
|
||||
data_dup_sorted = data_dup_sorted.drop_duplicates()
|
||||
|
||||
ymd_df = data_dup_sorted["ymd"]
|
||||
open_df = data_dup_sorted["open"]
|
||||
close_df = data_dup_sorted["close"]
|
||||
high_df = data_dup_sorted["high"]
|
||||
low_df = data_dup_sorted["low"]
|
||||
volume_df = data_dup_sorted["volume"]
|
||||
|
||||
min_price_list = [None for i in range(len(close_df)+51)]
|
||||
max_price_list = [None for i in range(len(close_df)+51)]
|
||||
for i in range(len(close_df)):
|
||||
if 480 < i:
|
||||
min_price_list[i], max_price_list[i] = self.get_Support_Resistance(close_df[i-120:i+1])
|
||||
|
||||
ymd = ymd_df.tolist()
|
||||
open = open_df.tolist()
|
||||
close = close_df.tolist()
|
||||
high = high_df.tolist()
|
||||
low = low_df.tolist()
|
||||
volume = volume_df.tolist()
|
||||
|
||||
open_scaled = (self.scaler.fit_transform(pd.DataFrame(open))).reshape(1,-1)[0]
|
||||
open_scaled = [0.0000000001 if c==0 else c for c in open_scaled]
|
||||
close_scaled = (self.scaler.fit_transform(pd.DataFrame(close))).reshape(1,-1)[0]
|
||||
close_scaled = [0.0000000001 if c == 0 else c for c in close_scaled]
|
||||
high_scaled = (self.scaler.fit_transform(pd.DataFrame(high))).reshape(1,-1)[0]
|
||||
high_scaled = [0.0000000001 if c == 0 else c for c in high_scaled]
|
||||
low_scaled = (self.scaler.fit_transform(pd.DataFrame(low))).reshape(1,-1)[0]
|
||||
low_scaled = [0.0000000001 if c == 0 else c for c in low_scaled]
|
||||
volume_scaled = (self.scaler.fit_transform(pd.DataFrame(volume))).reshape(1, -1)[0]
|
||||
volume_scaled = [0.0000000001 if c == 0 else c for c in volume_scaled]
|
||||
|
||||
if len(close_scaled) < 5:
|
||||
poly_5 = [0] * len(close_scaled)
|
||||
else:
|
||||
poly_5 = [0] * 4 + [np.polyfit(range(5), close_scaled[i - 4: i + 1], 1)[0] for i in range(4, len(close))]
|
||||
if len(close_scaled) < 10:
|
||||
poly_10 = [0] * len(close_scaled)
|
||||
else:
|
||||
poly_10 = [0] * 9 + [np.polyfit(range(10), close_scaled[i - 9: i + 1], 1)[0] for i in range(9, len(close))]
|
||||
if len(close_scaled) < 20:
|
||||
poly_20 = [0] * len(close_scaled)
|
||||
else:
|
||||
poly_20 = [0] * 19 + [np.polyfit(range(20), close_scaled[i - 19: i + 1], 1)[0] for i in range(19, len(close))]
|
||||
if len(poly_5) < 60:
|
||||
poly_60 = [0] * len(close_scaled)
|
||||
else:
|
||||
poly_60 = [0] * 59 + [np.polyfit(range(60), close_scaled[i - 59: i + 1], 1)[0] for i in range(59, len(close))]
|
||||
if len(close_scaled) < 120:
|
||||
poly_120 = [0] * len(close_scaled)
|
||||
else:
|
||||
poly_120 = [0] * 119 + [np.polyfit(range(120), close_scaled[i - 119: i + 1], 1)[0] for i in range(119, len(close))]
|
||||
if len(close_scaled) < 240:
|
||||
poly_240 = [0] * len(close_scaled)
|
||||
else:
|
||||
poly_240 = [0] * 239 + [np.polyfit(range(240), close_scaled[i - 239: i + 1], 1)[0] for i in range(239, len(close))]
|
||||
if len(close_scaled) < 480:
|
||||
poly_480 = [0] * len(close_scaled)
|
||||
else:
|
||||
poly_480 = [0] * 479 + [np.polyfit(range(480), close_scaled[i - 479: i + 1], 1)[0] for i in range(479, len(close))]
|
||||
|
||||
# ichimokuCloud
|
||||
df = pd.concat([pd.DataFrame(ymd), pd.DataFrame(open_scaled), pd.DataFrame(close_scaled), pd.DataFrame(high_scaled), pd.DataFrame(low_scaled), pd.DataFrame(volume_scaled)], axis=1)
|
||||
column_names = ['DATE', 'open', 'close', 'high', 'low', 'volume']
|
||||
df.columns = column_names
|
||||
c, b, l, s = 9, 26, 52, 26
|
||||
# 1. 전환선 = (과거 9일 동안 최고가 + 최저가) / 2
|
||||
# 당일을 포함한 9일 동안의 최고가와 최저가의 중간 값을 평균으로 나타낸다.
|
||||
changeLine = (df.high.rolling(c).max() + df.low.rolling(c).min()) / 2
|
||||
# 2. 기준선 = 과거 26일 동안 최고가 + 최저가) / 2
|
||||
# 당일을 포함한 26일 동안의 최고가와 최저가의 중간 값을 평균으로 나타낸다.
|
||||
baseLine = (df.high.rolling(b).max() + df.low.rolling(b).min()) / 2
|
||||
|
||||
# 3. 후행스팬 = 현재 close가격의 26일전 반영
|
||||
laggingSpan = [df.close.values[i + s] for i in range(len(df.close) - s)]
|
||||
laggingSpan += [None for i in range(s)]
|
||||
laggingSpan = np.array(laggingSpan)
|
||||
|
||||
# 4. 선행스팬 1 = ((기준선 + 전환선) / 2)를 26일 선행하여 배치
|
||||
# 전환선과 기준선의 평균값을 구해 당일 포함 26일 앞으로 이동시킨 선 (중-단기 구간의 힘을 보여줌)
|
||||
tmp_leadingSpan1 = (changeLine + baseLine) / 2
|
||||
""" S: 26일 선행시킴 """
|
||||
leadingSpan1 = list(tmp_leadingSpan1.values)
|
||||
for i in range(b - 1):
|
||||
leadingSpan1.insert(0, None)
|
||||
""" E: 26일 선행시킴 """
|
||||
|
||||
# 5. 선행스팬 2 = ((최근 52일 동안 최고가 + 최저가) / 2)를 26일 선행하여 배치
|
||||
# 당일을 포함한 52일 동안의 최고가와 최저가의 평균을 26일 앞으로 이동시킨 선 (장기으로 형성된 선이기 때문에 가장 느리게 변함)
|
||||
tmp_leadingSpan2 = (df.high.rolling(l).max() + df.low.rolling(l).min()) / 2
|
||||
""" S: 52일 선행시킴 """
|
||||
leadingSpan2 = list(tmp_leadingSpan2.values)
|
||||
for i in range(l - 1):
|
||||
leadingSpan2.insert(0, None)
|
||||
""" S: 52일 선행시킴 """
|
||||
|
||||
baseLine = baseLine.tolist()
|
||||
changeLine = changeLine.tolist()
|
||||
laggingSpan = list(laggingSpan)
|
||||
current_index = len(ymd)
|
||||
|
||||
for i in range(51):
|
||||
if len(ymd) < len(leadingSpan2):
|
||||
if mins == 1440:
|
||||
ymd.append(ymd[-1] + timedelta(days=1))
|
||||
else:
|
||||
ymd.append(ymd[-1] + timedelta(minutes=1))
|
||||
if len(open) < len(leadingSpan2):
|
||||
open.append(None)
|
||||
if len(close) < len(leadingSpan2):
|
||||
close.append(None)
|
||||
if len(high) < len(leadingSpan2):
|
||||
high.append(None)
|
||||
if len(low) < len(leadingSpan2):
|
||||
low.append(None)
|
||||
if len(volume) < len(leadingSpan2):
|
||||
volume.append(None)
|
||||
if len(baseLine) < len(leadingSpan2):
|
||||
baseLine.append(None)
|
||||
if len(changeLine) < len(leadingSpan2):
|
||||
changeLine.append(None)
|
||||
if len(laggingSpan) < len(leadingSpan2):
|
||||
laggingSpan.append(None)
|
||||
for i in range(26):
|
||||
if len(leadingSpan1) < len(leadingSpan2):
|
||||
leadingSpan1.append(leadingSpan1[-1])
|
||||
|
||||
# 7일 신고가
|
||||
new_high_7 = [0 for c in range(6)] + [1 if (changeLine[c - 1] is not None and changeLine[c] is not None and changeLine[c - 1] < changeLine[c]) and None not in close_scaled[c - 6:c + 1] and max(close_scaled[c - 6:c]) < close_scaled[c] else 0 for c in range(6, len(close_scaled))]
|
||||
# 9일 신고가
|
||||
new_high_9 = [0 for c in range(8)] + [1 if (changeLine[c - 1] is not None and changeLine[c] is not None and changeLine[c - 1] < changeLine[c]) and None not in close_scaled[c - 8:c + 1] and max(close_scaled[c - 8:c]) < close_scaled[c] else 0 for c in range(8, len(close_scaled))]
|
||||
# 26일 신고가
|
||||
new_high_26 = [0 for c in range(25)] + [1 if (baseLine[c - 1] is not None and baseLine[c] is not None and baseLine[c - 1] < baseLine[c]) and None not in close_scaled[c - 8:c + 1] and max(close_scaled[c - 25:c]) < close_scaled[c] else 0 for c in range(25, len(close_scaled))]
|
||||
# 33일 신고가
|
||||
new_high_33 = [0 for c in range(32)] + [1 if (leadingSpan1[c - 1] is not None and leadingSpan1[c] is not None and leadingSpan1[c - 1] < leadingSpan1[c]) and None not in close_scaled[c - 8:c + 1] and max(close_scaled[c - 32:c]) < close_scaled[c] else 0 for c in range(32, len(close_scaled))]
|
||||
# 52일 신고가
|
||||
new_high_52 = [0 for c in range(51)] + [1 if (leadingSpan2[c - 1] is not None and leadingSpan2[c] is not None and leadingSpan2[c - 1] < leadingSpan2[c]) and None not in close_scaled[c - 8:c + 1] and max(close_scaled[c - 51:c]) < close_scaled[c] else 0 for c in range(51, len(close_scaled))]
|
||||
|
||||
# 7일 신저가
|
||||
new_low_7 = [0 for c in range(6)] + [1 if (changeLine[c - 1] is not None and changeLine[c] is not None and changeLine[c - 1] < changeLine[c]) and None not in close_scaled[c - 6:c + 1] and close_scaled[c - 7] < min(close_scaled[c - 6:c + 1]) else 0 for c in range(6, len(close_scaled))]
|
||||
# 9일 신저가
|
||||
new_low_9 = [0 for c in range(8)] + [1 if (changeLine[c - 1] is not None and changeLine[c] is not None and changeLine[c - 1] < changeLine[c]) and None not in close_scaled[c - 8:c + 1] and close_scaled[c - 9] < min(close_scaled[c - 8:c + 1]) else 0 for c in range(8, len(close_scaled))]
|
||||
# 26일 신저가
|
||||
new_low_26 = [0 for c in range(25)] + [1 if (baseLine[c - 1] is not None and baseLine[c] is not None and baseLine[c - 1] < baseLine[c]) and None not in close_scaled[c - 8:c + 1] and close_scaled[c - 26] < min(close_scaled[c - 25:c + 1]) else 0 for c in range(25, len(close_scaled))]
|
||||
# 33일 신저가
|
||||
new_low_33 = [0 for c in range(32)] + [1 if (leadingSpan1[c - 1] is not None and leadingSpan1[c] is not None and leadingSpan1[c - 1] < leadingSpan1[c]) and None not in close_scaled[c - 8:c + 1] and close_scaled[c - 33] < min(close_scaled[c - 32:c + 1]) else 0 for c in range(32, len(close_scaled))]
|
||||
# 52일 신저가
|
||||
new_low_52 = [0 for c in range(51)] + [1 if (leadingSpan2[c - 1] is not None and leadingSpan2[c] is not None and leadingSpan2[c - 1] < leadingSpan2[c]) and None not in close_scaled[c - 8:c + 1] and close_scaled[c - 52] < min(close_scaled[c - 51:c + 1]) else 0 for c in range(51, len(close_scaled))]
|
||||
|
||||
# 이동 평균
|
||||
close_df = pd.DataFrame(close_scaled)
|
||||
avg5 = list(np.reshape(close_df.ewm(5).mean().values, -1))
|
||||
avg10 = list(np.reshape(close_df.ewm(10).mean().values, -1))
|
||||
avg20 = list(np.reshape(close_df.ewm(20).mean().values, -1))
|
||||
avg60 = list(np.reshape(close_df.ewm(60).mean().values, -1))
|
||||
avg90 = list(np.reshape(close_df.ewm(90).mean().values, -1))
|
||||
avg120 = list(np.reshape(close_df.ewm(120).mean().values, -1))
|
||||
avg240 = list(np.reshape(close_df.ewm(240).mean().values, -1))
|
||||
avg360 = list(np.reshape(close_df.ewm(360).mean().values, -1))
|
||||
avg480 = list(np.reshape(close_df.ewm(480).mean().values, -1))
|
||||
avg720 = list(np.reshape(close_df.ewm(720).mean().values, -1))
|
||||
avg1440 = list(np.reshape(close_df.ewm(1440).mean().values, -1))
|
||||
avg2880 = list(np.reshape(close_df.ewm(2880).mean().values, -1))
|
||||
|
||||
# 이격도
|
||||
disparity_avg5_df = (close_df / close_df.ewm(span=5, min_periods=5, adjust=False).mean())
|
||||
disparity_avg20_df = (close_df / close_df.ewm(span=20, min_periods=20, adjust=False).mean())
|
||||
disparity_avg60_df = (close_df / close_df.ewm(span=60, min_periods=60, adjust=False).mean())
|
||||
disparity_avg120_df = (close_df / close_df.ewm(span=120, min_periods=120, adjust=False).mean())
|
||||
disparity_avg240_df = (close_df / close_df.ewm(span=240, min_periods=240, adjust=False).mean())
|
||||
disparity_avg480_df = (close_df / close_df.ewm(span=480, min_periods=480, adjust=False).mean())
|
||||
disparity_avg1440_df = (close_df / close_df.ewm(span=1440, min_periods=1440, adjust=False).mean())
|
||||
|
||||
disparity_480_loc = [0 for i in range(len(close))]
|
||||
disparity_1440_loc = [0 for i in range(len(close))]
|
||||
disparity_avg480_list = list(disparity_avg480_df.values.reshape(-1))
|
||||
disparity_avg1440_list = list(disparity_avg1440_df.values.reshape(-1))
|
||||
for i in range(0, len(close)):
|
||||
if 2880 < i:
|
||||
l = [d for d in disparity_avg480_list[i - 1440:i + 1]]
|
||||
min_v = np.min(l)
|
||||
max_v = np.max(l)
|
||||
disparity_480_loc[i] = (disparity_avg480_list[i] - min_v) / (max_v - min_v)
|
||||
l = [d for d in disparity_avg1440_list[i - 1440:i + 1]]
|
||||
min_v = np.min(l)
|
||||
max_v = np.max(l)
|
||||
disparity_1440_loc[i] = (disparity_avg1440_list[i] - min_v) / (max_v - min_v)
|
||||
|
||||
disparity_480_loc_df = pd.DataFrame(disparity_480_loc)
|
||||
disparity_1440_loc_df = pd.DataFrame(disparity_1440_loc)
|
||||
|
||||
disparity_avg5_list = list(disparity_avg5_df.values.reshape(-1))
|
||||
disparity_avg20_list = list(disparity_avg20_df.values.reshape(-1))
|
||||
disparity_avg60_list = list(disparity_avg60_df.values.reshape(-1))
|
||||
disparity_avg120_list = list(disparity_avg120_df.values.reshape(-1))
|
||||
disparity_avg240_list = list(disparity_avg240_df.values.reshape(-1))
|
||||
disparity_avg480_list = list(disparity_avg480_df.values.reshape(-1))
|
||||
disparity_avg1440_list = list(disparity_avg1440_df.values.reshape(-1))
|
||||
|
||||
disparity_diff_20_5, disparity_diff_20_5_rate = self.getDiff_Rate(disparity_avg20_list, disparity_avg5_list, duration=20)
|
||||
disparity_diff_60_20, disparity_diff_60_20_rate = self.getDiff_Rate(disparity_avg60_list, disparity_avg20_list, duration=60)
|
||||
disparity_diff_120_20, disparity_diff_120_20_rate = self.getDiff_Rate(disparity_avg120_list, disparity_avg20_list, duration=120)
|
||||
disparity_diff_240_20, disparity_diff_240_20_rate = self.getDiff_Rate(disparity_avg240_list, disparity_avg20_list, duration=240)
|
||||
disparity_diff_480_20, disparity_diff_480_20_rate = self.getDiff_Rate(disparity_avg480_list, disparity_avg20_list, duration=480)
|
||||
disparity_diff_1440_20, disparity_diff_1440_20_rate = self.getDiff_Rate(disparity_avg1440_list, disparity_avg20_list, duration=1440)
|
||||
|
||||
np_high, np_low, np_close = np.array(high_scaled, dtype=np.float64), np.array(low_scaled, dtype=np.float64), np.array(close_scaled, dtype=np.float64)
|
||||
slowk_5_df, slowd_5_df = talib.STOCH(np_high, np_low, np_close, fastk_period=5, slowk_period=3, slowk_matype=0, slowd_period=3, slowd_matype=0)
|
||||
slowk_10_df, slowd_10_df = talib.STOCH(np_high, np_low, np_close, fastk_period=10, slowk_period=6, slowk_matype=0, slowd_period=6, slowd_matype=0)
|
||||
slowk_20_df, slowd_20_df = talib.STOCH(np_high, np_low, np_close, fastk_period=20, slowk_period=12, slowk_matype=0, slowd_period=12, slowd_matype=0)
|
||||
slowk_60_df, slowd_60_df = talib.STOCH(np_high, np_low, np_close, fastk_period=60, slowk_period=37, slowk_matype=0, slowd_period=37, slowd_matype=0)
|
||||
slowk_120_df, slowd_120_df = talib.STOCH(np_high, np_low, np_close, fastk_period=120, slowk_period=74, slowk_matype=0, slowd_period=74, slowd_matype=0)
|
||||
slowk_240_df, slowd_240_df = talib.STOCH(np_high, np_low, np_close, fastk_period=240, slowk_period=148, slowk_matype=0, slowd_period=148, slowd_matype=0)
|
||||
slowk_480_df, slowd_480_df = talib.STOCH(np_high, np_low, np_close, fastk_period=480, slowk_period=296, slowk_matype=0, slowd_period=296, slowd_matype=0)
|
||||
|
||||
# 최고/최저 위치
|
||||
loc_240 = [None for i in range(len(close))]
|
||||
for i in range(240, len(close)):
|
||||
min_v = np.min(close_scaled[i - 239:i + 1])
|
||||
max_v = np.max(close_scaled[i - 239:i + 1])
|
||||
if close[i] is not None:
|
||||
loc_240[i] = ((close_scaled[i] - min_v) / (max_v - min_v))
|
||||
else:
|
||||
loc_240[i] = None
|
||||
|
||||
loc_240 = pd.DataFrame(loc_240)
|
||||
loc_240_k = loc_240.to_numpy().reshape(-1)
|
||||
loc_240_d = loc_240.rolling(20).mean()
|
||||
loc_240_s = loc_240.rolling(60).mean()
|
||||
loc_240_d = loc_240_d.to_numpy().reshape(-1)
|
||||
loc_240_s = loc_240_s.to_numpy().reshape(-1)
|
||||
|
||||
n, t = 20, 2
|
||||
max_20 = close_df.rolling(window=n).mean()
|
||||
stddev_20 = close_df.rolling(window=n).std()
|
||||
upper_20 = max_20 + (stddev_20 * t) # 상단 볼리저 밴드
|
||||
lower_20 = max_20 - (stddev_20 * t) # 하단 볼리저 밴드
|
||||
middle_20 = (upper_20 + lower_20) / 2
|
||||
|
||||
width_df = (upper_20 - lower_20) / middle_20
|
||||
width_min = np.min(width_df[0])
|
||||
width_max = np.max(width_df[0])
|
||||
bb_width_df = 100 * (width_df - width_min) / (width_max - width_min)
|
||||
bb_pb_df = 100 * (close_df - lower_20) / (upper_20 - lower_20)
|
||||
|
||||
upper_20 = list(np.reshape(upper_20.values, -1))
|
||||
lower_20 = list(np.reshape(lower_20.values, -1))
|
||||
middle_20 = list(np.reshape(middle_20.values, -1))
|
||||
|
||||
duration = 1440
|
||||
if mins == 1440:
|
||||
duration = 360
|
||||
laggingSpan_close_diff, laggingSpan_close_diff_rate = self.getDiff_Rate(laggingSpan, close_scaled, duration=duration)
|
||||
laggingSpan_changeLine_diff, laggingSpan_changeLine_diff_rate = self.getDiff_Rate(laggingSpan, changeLine, duration=duration)
|
||||
laggingSpan_baseLine_diff, laggingSpan_baseLine_diff_rate = self.getDiff_Rate(laggingSpan, baseLine, duration=duration)
|
||||
laggingSpan_leadingSpan1_diff, laggingSpan_leadingSpan1_diff_rate = self.getDiff_Rate(laggingSpan, leadingSpan1, duration=duration)
|
||||
laggingSpan_leadingSpan2_diff, laggingSpan_leadingSpan2_diff_rate = self.getDiff_Rate(laggingSpan, leadingSpan2, duration=duration)
|
||||
laggingSpan_avg60_diff, laggingSpan_avg60_diff_rate = self.getDiff_Rate(laggingSpan, avg60, duration=duration)
|
||||
laggingSpan_lower20_diff, laggingSpan_lower20_diff_rate = self.getDiff_Rate(laggingSpan, lower_20, duration=duration)
|
||||
laggingSpan_middle20_diff, laggingSpan_middle20_diff_rate = self.getDiff_Rate(laggingSpan, middle_20, duration=duration)
|
||||
laggingSpan_upper20_diff, laggingSpan_upper20_diff_rate = self.getDiff_Rate(laggingSpan, upper_20, duration=duration)
|
||||
baseLine_close_diff, baseLine_close_diff_rate = self.getDiff_Rate(baseLine, close_scaled, duration=duration)
|
||||
changeLine_close_diff, changeLine_close_diff_rate = self.getDiff_Rate(changeLine, close_scaled, duration=duration)
|
||||
changeLine_baseLine_diff, changeLine_baseLine_diff_rate = self.getDiff_Rate(changeLine, baseLine, duration=duration)
|
||||
changeLine_leadingSpan1_diff, changeLine_leadingSpan1_diff_rate = self.getDiff_Rate(changeLine, leadingSpan1, duration=duration)
|
||||
leadingSpan1_leadingSpan2_diff, leadingSpan1_leadingSpan2_diff_rate = self.getDiff_Rate(leadingSpan1, leadingSpan2, duration=duration)
|
||||
|
||||
df_list = [
|
||||
pd.DataFrame(ymd),
|
||||
pd.DataFrame(open_scaled), pd.DataFrame(close_scaled), pd.DataFrame(high_scaled), pd.DataFrame(low_scaled), pd.DataFrame(volume_scaled),
|
||||
pd.DataFrame(changeLine), pd.DataFrame(baseLine), pd.DataFrame(laggingSpan), pd.DataFrame(leadingSpan1), pd.DataFrame(leadingSpan2),
|
||||
|
||||
pd.DataFrame(laggingSpan_close_diff),
|
||||
pd.DataFrame(laggingSpan_changeLine_diff),
|
||||
pd.DataFrame(laggingSpan_baseLine_diff),
|
||||
pd.DataFrame(laggingSpan_leadingSpan1_diff),
|
||||
pd.DataFrame(laggingSpan_leadingSpan2_diff),
|
||||
pd.DataFrame(laggingSpan_avg60_diff),
|
||||
pd.DataFrame(laggingSpan_lower20_diff),
|
||||
pd.DataFrame(laggingSpan_middle20_diff),
|
||||
pd.DataFrame(laggingSpan_upper20_diff),
|
||||
pd.DataFrame(baseLine_close_diff),
|
||||
pd.DataFrame(changeLine_close_diff),
|
||||
pd.DataFrame(changeLine_baseLine_diff),
|
||||
pd.DataFrame(changeLine_leadingSpan1_diff),
|
||||
pd.DataFrame(leadingSpan1_leadingSpan2_diff),
|
||||
|
||||
pd.DataFrame(laggingSpan_close_diff_rate),
|
||||
pd.DataFrame(laggingSpan_changeLine_diff_rate),
|
||||
pd.DataFrame(laggingSpan_baseLine_diff_rate),
|
||||
pd.DataFrame(laggingSpan_leadingSpan1_diff_rate),
|
||||
pd.DataFrame(laggingSpan_leadingSpan2_diff_rate),
|
||||
pd.DataFrame(laggingSpan_avg60_diff_rate),
|
||||
pd.DataFrame(laggingSpan_lower20_diff_rate),
|
||||
pd.DataFrame(laggingSpan_middle20_diff_rate),
|
||||
pd.DataFrame(laggingSpan_upper20_diff_rate),
|
||||
pd.DataFrame(baseLine_close_diff_rate),
|
||||
pd.DataFrame(changeLine_close_diff_rate),
|
||||
pd.DataFrame(changeLine_baseLine_diff_rate),
|
||||
pd.DataFrame(changeLine_leadingSpan1_diff_rate),
|
||||
pd.DataFrame(leadingSpan1_leadingSpan2_diff_rate),
|
||||
|
||||
pd.DataFrame(loc_240_k), pd.DataFrame(loc_240_d), pd.DataFrame(loc_240_s),
|
||||
|
||||
pd.DataFrame(avg5), pd.DataFrame(avg10), pd.DataFrame(avg20), pd.DataFrame(avg60), pd.DataFrame(avg90), pd.DataFrame(avg120), pd.DataFrame(avg240), pd.DataFrame(avg360), pd.DataFrame(avg480), pd.DataFrame(avg720), pd.DataFrame(avg1440), pd.DataFrame(avg2880),
|
||||
disparity_avg5_df, disparity_avg20_df, disparity_avg60_df, disparity_avg120_df, disparity_avg240_df, disparity_avg480_df, disparity_avg1440_df, disparity_480_loc_df, disparity_1440_loc_df,
|
||||
|
||||
pd.DataFrame(disparity_diff_20_5), pd.DataFrame(disparity_diff_20_5_rate),
|
||||
pd.DataFrame(disparity_diff_60_20), pd.DataFrame(disparity_diff_60_20_rate),
|
||||
pd.DataFrame(disparity_diff_120_20), pd.DataFrame(disparity_diff_120_20_rate),
|
||||
pd.DataFrame(disparity_diff_240_20), pd.DataFrame(disparity_diff_240_20_rate),
|
||||
pd.DataFrame(disparity_diff_480_20), pd.DataFrame(disparity_diff_480_20_rate),
|
||||
pd.DataFrame(disparity_diff_1440_20), pd.DataFrame(disparity_diff_1440_20_rate),
|
||||
|
||||
pd.DataFrame(upper_20), pd.DataFrame(lower_20), pd.DataFrame(middle_20),
|
||||
bb_width_df, bb_pb_df,
|
||||
|
||||
pd.DataFrame(new_high_7), pd.DataFrame(new_high_9), pd.DataFrame(new_high_26), pd.DataFrame(new_high_33), pd.DataFrame(new_high_52),
|
||||
pd.DataFrame(new_low_7), pd.DataFrame(new_low_9), pd.DataFrame(new_low_26), pd.DataFrame(new_low_33), pd.DataFrame(new_low_52),
|
||||
pd.DataFrame(slowk_5_df), pd.DataFrame(slowd_5_df),
|
||||
pd.DataFrame(slowk_10_df), pd.DataFrame(slowd_10_df),
|
||||
pd.DataFrame(slowk_20_df), pd.DataFrame(slowd_20_df),
|
||||
pd.DataFrame(slowk_60_df), pd.DataFrame(slowd_60_df),
|
||||
pd.DataFrame(slowk_120_df), pd.DataFrame(slowd_120_df),
|
||||
pd.DataFrame(slowk_240_df), pd.DataFrame(slowd_240_df),
|
||||
pd.DataFrame(slowk_480_df), pd.DataFrame(slowd_480_df),
|
||||
|
||||
pd.DataFrame(min_price_list), pd.DataFrame(max_price_list),
|
||||
pd.DataFrame(poly_5), pd.DataFrame(poly_10), pd.DataFrame(poly_20), pd.DataFrame(poly_60), pd.DataFrame(poly_120), pd.DataFrame(poly_240), pd.DataFrame(poly_480)
|
||||
|
||||
]
|
||||
|
||||
data = pd.concat(df_list, axis=1)
|
||||
column_names = [
|
||||
'ymd',
|
||||
'open', 'close', 'high', 'low', 'volume',
|
||||
'changeLine', 'baseLine', 'laggingSpan', 'leadingSpan1', 'leadingSpan2',
|
||||
|
||||
'laggingSpan_close_diff',
|
||||
'laggingSpan_changeLine_diff',
|
||||
'laggingSpan_baseLine_diff',
|
||||
'laggingSpan_leadingSpan1_diff',
|
||||
'laggingSpan_leadingSpan2_diff',
|
||||
'laggingSpan_avg60_diff',
|
||||
'laggingSpan_lower20_diff',
|
||||
'laggingSpan_middle20_diff',
|
||||
'laggingSpan_upper20_diff',
|
||||
'baseLine_close_diff',
|
||||
'changeLine_close_diff',
|
||||
'changeLine_baseLine_diff',
|
||||
'changeLine_leadingSpan1_diff',
|
||||
'leadingSpan1_leadingSpan2_diff',
|
||||
|
||||
'laggingSpan_close_diff_rate',
|
||||
'laggingSpan_changeLine_diff_rate',
|
||||
'laggingSpan_baseLine_diff_rate',
|
||||
'laggingSpan_leadingSpan1_diff_rate',
|
||||
'laggingSpan_leadingSpan2_diff_rate',
|
||||
'laggingSpan_avg60_diff_rate',
|
||||
'laggingSpan_lower20_diff_rate',
|
||||
'laggingSpan_middle20_diff_rate',
|
||||
'laggingSpan_upper20_diff_rate',
|
||||
'baseLine_close_diff_rate',
|
||||
'changeLine_close_diff_rate',
|
||||
'changeLine_baseLine_diff_rate',
|
||||
'changeLine_leadingSpan1_diff_rate',
|
||||
'leadingSpan1_leadingSpan2_diff_rate',
|
||||
|
||||
'loc_240_k', 'loc_240_d', 'loc_240_s',
|
||||
|
||||
'avg5', 'avg10', 'avg20', 'avg60', 'avg90', 'avg120', 'avg240', 'avg360', 'avg480', 'avg720', 'avg1440', 'avg2880',
|
||||
'disparity_avg5', 'disparity_avg20', 'disparity_avg60', 'disparity_avg120', 'disparity_avg240', 'disparity_avg480', 'disparity_avg1440', 'disparity_480_loc', 'disparity_1440_loc',
|
||||
'disparity_diff_20_5', 'disparity_diff_20_5_rate',
|
||||
'disparity_diff_60_20', 'disparity_diff_60_20_rate',
|
||||
'disparity_diff_120_20', 'disparity_diff_120_20_rate',
|
||||
'disparity_diff_240_20', 'disparity_diff_240_20_rate',
|
||||
'disparity_diff_480_20', 'disparity_diff_480_20_rate',
|
||||
'disparity_diff_1440_20', 'disparity_diff_1440_20_rate',
|
||||
|
||||
'upper_20', 'lower_20', 'middle_20',
|
||||
'bb_width', 'bb_pb',
|
||||
|
||||
'new_high_7', 'new_high_9', 'new_high_26', 'new_high_33', 'new_high_52',
|
||||
'new_low_7', 'new_low_9', 'new_low_26', 'new_low_33', 'new_low_52',
|
||||
|
||||
'slowk_5', 'slowd_5',
|
||||
'slowk_10', 'slowd_10',
|
||||
'slowk_20', 'slowd_20',
|
||||
'slowk_60', 'slowd_60',
|
||||
'slowk_120', 'slowd_120',
|
||||
'slowk_240', 'slowd_240',
|
||||
'slowk_480', 'slowd_480',
|
||||
|
||||
|
||||
'min_price', 'max_price',
|
||||
'poly_5', 'poly_10', 'poly_20', 'poly_60', 'poly_120', 'poly_240', 'poly_480'
|
||||
]
|
||||
data.columns = column_names
|
||||
data.index = pd.DatetimeIndex(ymd)
|
||||
|
||||
return data, current_index
|
||||
|
||||
|
||||
def getData(self, ticker, mins=None, ymd=None, get_days=14):
|
||||
if ymd is None:
|
||||
result = self.getCoinData(ticker, mins=mins, get_days=get_days)
|
||||
else:
|
||||
result = self.getCoinData(ticker, mins=mins, ymd=ymd, get_days=get_days)
|
||||
|
||||
if len(result['ymd']) < 1:
|
||||
return None, None
|
||||
|
||||
#result_tic = self.makeTickData(result_m1, mins=minute)
|
||||
data_scale, ci = self.analyze_scale(result)
|
||||
data, ci = self.analyze_raw(result)
|
||||
|
||||
return data, data_scale, ci
|
||||
641
JSDPattern_minutely.py
Normal file
641
JSDPattern_minutely.py
Normal file
@@ -0,0 +1,641 @@
|
||||
# https://bibot.tistory.com/63
|
||||
# https://nonmeyet.tistory.com/entry/Python-TALib%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-%EB%B9%84%ED%8A%B8%EC%BD%94%EC%9D%B8%EC%A3%BC%EA%B0%80%EA%B8%B0%EC%88%A0%EB%B6%84%EC%84%9D-%EB%B3%B4%EC%A1%B0%EC%A7%80%ED%91%9C-%EC%B6%94%EA%B0%80
|
||||
# https://lunadaddy.tistory.com/122
|
||||
# https://wikidocs.net/186885
|
||||
|
||||
import numpy as np
|
||||
np.seterr(divide='ignore', invalid='ignore')
|
||||
from scipy.signal import argrelextrema
|
||||
# https://www.lfd.uci.edu/~gohlke/pythonlibs/#ta-lib
|
||||
# https://lunadaddy.tistory.com/122
|
||||
import talib
|
||||
|
||||
import pandas as pd
|
||||
from datetime import datetime, timedelta
|
||||
from sklearn.preprocessing import MinMaxScaler
|
||||
|
||||
from JSDPattern import JSDPattern
|
||||
|
||||
class JSDPattern_minutely (JSDPattern):
|
||||
|
||||
scaler = None
|
||||
|
||||
def __init__(self, RESOURCE_PATH=None):
|
||||
super().__init__(RESOURCE_PATH)
|
||||
self.scaler = MinMaxScaler()
|
||||
|
||||
return
|
||||
|
||||
def get_Support_Resistance(self, df):
|
||||
n = 10
|
||||
support_df = df.iloc[argrelextrema(df.values, np.less_equal, order=n)[0]]
|
||||
resistance_df = df.iloc[argrelextrema(df.values, np.greater_equal, order=n)[0]]
|
||||
|
||||
support, resistance = np.zeros(len(df)), np.zeros(len(df))
|
||||
support[0], resistance[0] = df[0].iloc[0], df[0].iloc[0]
|
||||
s_i, r_i = 0, 0
|
||||
for i in range(1, len(df)):
|
||||
if s_i < len(support_df) and df.index[i] == support_df.index[s_i]:
|
||||
support[i] = support_df[0].iloc[s_i]
|
||||
s_i += 1
|
||||
else:
|
||||
support[i] = support[i-1]
|
||||
|
||||
if r_i < len(resistance_df) and df.index[i] == resistance_df.index[r_i]:
|
||||
resistance[i] = resistance_df[0].iloc[r_i]
|
||||
r_i += 1
|
||||
else:
|
||||
resistance[i] = resistance[i-1]
|
||||
|
||||
return support, resistance
|
||||
|
||||
def analyze_raw(self, result):
|
||||
result["volume"] = [result["volume"][i] if 0 < result["volume"][i] else 1 for i in range(len(result["volume"]))]
|
||||
# 기본 캔들 정보
|
||||
open_df = pd.DataFrame(result["open"])
|
||||
close_df = pd.DataFrame(result["close"])
|
||||
high_df = pd.DataFrame(result["high"])
|
||||
low_df = pd.DataFrame(result["low"])
|
||||
volume_df = pd.DataFrame(result["volume"])
|
||||
|
||||
# 중복 제거
|
||||
ymd_df = pd.DataFrame(result["ymd"])
|
||||
data_dup = pd.concat([ymd_df, open_df, close_df, high_df, low_df, volume_df], axis=1)
|
||||
data_dup.columns = ["ymd", "open", "close", "high", "low", "volume"]
|
||||
data_dup.index = pd.DatetimeIndex(result["ymd"])
|
||||
data_dup_sorted = data_dup.sort_index(ascending=True)
|
||||
data_dup_sorted = data_dup_sorted.drop_duplicates()
|
||||
|
||||
ymd_df = data_dup_sorted["ymd"]
|
||||
open_df = data_dup_sorted["open"]
|
||||
close_df = data_dup_sorted["close"]
|
||||
high_df = data_dup_sorted["high"]
|
||||
low_df = data_dup_sorted["low"]
|
||||
volume_df = data_dup_sorted["volume"]
|
||||
|
||||
ymd = ymd_df.tolist()
|
||||
open = open_df.tolist()
|
||||
close = close_df.tolist()
|
||||
high = high_df.tolist()
|
||||
low = low_df.tolist()
|
||||
volume = volume_df.tolist()
|
||||
|
||||
volume_rate = np.zeros(len(close))
|
||||
head_rate, body_rate, tail_rate = np.zeros(len(close)), np.zeros(len(close)), np.zeros(len(close))
|
||||
open_low_rate, open_high_rate, open_open_rate, open_close_rate = np.zeros(len(close)), np.zeros(len(close)), np.zeros(len(close)), np.zeros(len(close))
|
||||
close_low_rate, close_high_rate, close_open_rate, close_close_rate = np.zeros(len(close)), np.zeros(len(close)), np.zeros(len(close)), np.zeros(len(close))
|
||||
for i in range(len(close)):
|
||||
length = high[i] - low[i]
|
||||
|
||||
if 0 < length:
|
||||
max_value = max(open[i], close[i])
|
||||
min_value = min(open[i], close[i])
|
||||
|
||||
head_rate[i] = (high[i] - max_value) / length
|
||||
body_rate[i] = (max_value - min_value) / length
|
||||
tail_rate[i] = (min_value - low[i]) / length
|
||||
|
||||
if 0 < i:
|
||||
if 0 < volume[i-1]:
|
||||
volume_rate[i] = volume[i]/volume[i-1]
|
||||
open_low_rate[i] = (low[i] - open[i-1])/open[i-1]
|
||||
open_high_rate[i] = (high[i] - open[i-1])/open[i-1]
|
||||
open_open_rate[i] = (open[i] - open[i-1])/open[i-1]
|
||||
open_close_rate[i] = (close[i] - open[i-1])/open[i-1]
|
||||
close_low_rate[i] = (low[i] - close[i-1])/close[i-1]
|
||||
close_high_rate[i] = (high[i] - close[i-1])/close[i-1]
|
||||
close_open_rate[i] = (open[i] - close[i-1])/close[i-1]
|
||||
close_close_rate[i] = (close[i] - close[i-1])/close[i-1]
|
||||
|
||||
|
||||
support, resistance = self.get_Support_Resistance(pd.DataFrame(close))
|
||||
|
||||
#z = np.polyfit(df['speed'], df['dist'], 1) # 기울기와 절편 확인
|
||||
#f = np.poly1d(z) # f(x): f함수
|
||||
if 5 < len(close):
|
||||
poly_5 = [0] * 4 + [np.polyfit(range(5), close[i - 4: i + 1], 1)[0] for i in range(4, len(close))]
|
||||
else:
|
||||
poly_5 = [0] * len(close)
|
||||
if 10 < len(close):
|
||||
poly_10 = [0] * 9 + [np.polyfit(range(10), close[i - 9: i + 1], 1)[0] for i in range(9, len(close))]
|
||||
else:
|
||||
poly_10 = [0] * len(close)
|
||||
if 20 < len(close):
|
||||
poly_20 = [0] * 19 + [np.polyfit(range(20), close[i - 19: i + 1], 1)[0] for i in range(19, len(close))]
|
||||
else:
|
||||
poly_20 = [0] * len(close)
|
||||
if 60 < len(close):
|
||||
poly_60 = [0] * 59 + [np.polyfit(range(60), close[i - 59: i + 1], 1)[0] for i in range(59, len(close))]
|
||||
else:
|
||||
poly_60 = [0] * len(close)
|
||||
if 120 < len(close):
|
||||
poly_120 = [0] * 119 + [np.polyfit(range(120), close[i - 119: i + 1], 1)[0] for i in range(119, len(close))]
|
||||
else:
|
||||
poly_120 = [0] * len(close)
|
||||
if 240 < len(close):
|
||||
poly_240 = [0] * 239 + [np.polyfit(range(240), close[i - 239: i + 1], 1)[0] for i in range(239, len(close))]
|
||||
else:
|
||||
poly_240 = [0] * len(close)
|
||||
if 480 < len(close):
|
||||
poly_480 = [0] * 479 + [np.polyfit(range(480), close[i - 479: i + 1], 1)[0] for i in range(479, len(close))]
|
||||
else:
|
||||
poly_480 = [0] * len(close)
|
||||
if 720 < len(close):
|
||||
poly_720 = [0] * 719 + [np.polyfit(range(720), close[i - 719: i + 1], 1)[0] for i in range(719, len(close))]
|
||||
else:
|
||||
poly_720 = [0] * len(close)
|
||||
if 1440 < len(close):
|
||||
poly_1440 = [0] * 1439 + [np.polyfit(range(1440), close[i - 1439: i + 1], 1)[0] for i in range(1439, len(close))]
|
||||
else:
|
||||
poly_1440 = [0] * len(close)
|
||||
|
||||
# 7일 신고가
|
||||
new_high_7 = [0 for c in range(6)] + [1 if (close[c - 1] is not None and close[c] is not None and close[c - 1] < close[c]) and None not in close[c - 6:c + 1] and max(close[c - 6:c]) < close[c] else 0 for c in range(6, len(close))]
|
||||
# 9일 신고가
|
||||
new_high_9 = [0 for c in range(8)] + [1 if (close[c - 1] is not None and close[c] is not None and close[c - 1] < close[c]) and None not in close[c - 8:c + 1] and max(close[c - 8:c]) < close[c] else 0 for c in range(8, len(close))]
|
||||
# 26일 신고가
|
||||
new_high_26 = [0 for c in range(25)] + [1 if (close[c - 1] is not None and close[c] is not None and close[c - 1] < close[c]) and None not in close[c - 25:c + 1] and max(close[c - 25:c]) < close[c] else 0 for c in range(25, len(close))]
|
||||
|
||||
# 7일 신저가
|
||||
new_low_7 = [0 for c in range(6)] + [1 if (close[c - 1] is not None and close[c] is not None and close[c - 1] < close[c]) and None not in close[c - 6:c + 1] and close[c - 6] < min(close[c - 6:c + 1]) else 0 for c in range(6, len(close))]
|
||||
# 9일 신저가
|
||||
new_low_9 = [0 for c in range(8)] + [1 if (close[c - 1] is not None and close[c] is not None and close[c - 1] < close[c]) and None not in close[c - 8:c + 1] and close[c - 8] < min(close[c - 8:c + 1]) else 0 for c in range(8, len(close))]
|
||||
# 26일 신저가
|
||||
new_low_26 = [0 for c in range(25)] + [1 if (close[c - 1] is not None and close[c] is not None and close[c - 1] < close[c]) and None not in close[c - 25:c + 1] and close[c - 25] < min(close[c - 25:c + 1]) else 0 for c in range(25, len(close))]
|
||||
|
||||
high_th = [0]
|
||||
for i in range(1, len(close)):
|
||||
count = 0
|
||||
for c in range(i - 1, i - 30, -1):
|
||||
if c < 0:
|
||||
break
|
||||
if close[i] < close[c]:
|
||||
break
|
||||
else:
|
||||
count += 1
|
||||
high_th.append(count)
|
||||
|
||||
# 이동 평균
|
||||
close_df = pd.DataFrame(close)
|
||||
|
||||
avg5_df = close_df.ewm(5).mean()
|
||||
avg10_df = close_df.ewm(10).mean()
|
||||
avg20_df = close_df.ewm(20).mean()
|
||||
avg60_df = close_df.ewm(60).mean()
|
||||
avg120_df = close_df.ewm(120).mean()
|
||||
avg240_df = close_df.ewm(240).mean()
|
||||
avg480_df = close_df.ewm(480).mean()
|
||||
avg720_df = close_df.ewm(720).mean()
|
||||
avg1440_df = close_df.ewm(1440).mean()
|
||||
|
||||
# 이격도
|
||||
disparity_avg5_df = (close_df / close_df.ewm(span=5, min_periods=5, adjust=False).mean())
|
||||
disparity_avg5_df = disparity_avg5_df.replace({None: np.nan})
|
||||
disparity_avg20_df = (close_df / close_df.ewm(span=20, min_periods=20, adjust=False).mean())
|
||||
disparity_avg20_df = disparity_avg20_df.replace({None: np.nan})
|
||||
disparity_avg60_df = (close_df / close_df.ewm(span=60, min_periods=60, adjust=False).mean())
|
||||
disparity_avg60_df = disparity_avg60_df.replace({None: np.nan})
|
||||
disparity_avg120_df = (close_df / close_df.ewm(span=120, min_periods=120, adjust=False).mean())
|
||||
disparity_avg120_df = disparity_avg120_df.replace({None: np.nan})
|
||||
disparity_avg240_df = (close_df / close_df.ewm(span=240, min_periods=240, adjust=False).mean())
|
||||
disparity_avg240_df = disparity_avg240_df.replace({None: np.nan})
|
||||
disparity_avg480_df = (close_df / close_df.ewm(span=480, min_periods=480, adjust=False).mean())
|
||||
disparity_avg480_df = disparity_avg480_df.replace({None: np.nan})
|
||||
disparity_avg720_df = (close_df / close_df.ewm(span=720, min_periods=720, adjust=False).mean())
|
||||
disparity_avg720_df = disparity_avg720_df.replace({None: np.nan})
|
||||
disparity_avg1440_df = (close_df / close_df.ewm(span=1440, min_periods=1440, adjust=False).mean())
|
||||
disparity_avg1440_df = disparity_avg1440_df.replace({None: np.nan})
|
||||
disparity_avg2880_df = (close_df / close_df.ewm(span=2880, min_periods=2880, adjust=False).mean())
|
||||
disparity_avg2880_df = disparity_avg2880_df.replace({None: np.nan})
|
||||
|
||||
|
||||
""""""
|
||||
n, t = 20, 2
|
||||
max_20 = close_df.rolling(window=n).mean()
|
||||
stddev_20 = close_df.rolling(window=n).std()
|
||||
upper_20 = max_20 + (stddev_20 * t) # 상단 볼리저 밴드
|
||||
lower_20 = max_20 - (stddev_20 * t) # 하단 볼리저 밴드
|
||||
middle_20 = (upper_20 + lower_20) / 2
|
||||
|
||||
width_df = (upper_20 - lower_20) / middle_20
|
||||
width_min = np.min(width_df[0])
|
||||
width_max = np.max(width_df[0])
|
||||
bb_width_df = 100 * (width_df - width_min) / (width_max - width_min)
|
||||
bb_pb_df = 100 * (close_df - lower_20) / (upper_20 - lower_20)
|
||||
|
||||
upper_20 = list(np.reshape(upper_20.values, -1))
|
||||
lower_20 = list(np.reshape(lower_20.values, -1))
|
||||
middle_20 = list(np.reshape(middle_20.values, -1))
|
||||
|
||||
np_high, np_low, np_close = np.array(high, dtype=np.float64), np.array(low, dtype=np.float64), np.array(close, dtype=np.float64)
|
||||
slowk_5_df, slowd_5_df = talib.STOCH(np_high, np_low, np_close, fastk_period=5, slowk_period=3, slowk_matype=0, slowd_period=3, slowd_matype=0)
|
||||
slowk_10_df, slowd_10_df = talib.STOCH(np_high, np_low, np_close, fastk_period=10, slowk_period=6, slowk_matype=0, slowd_period=6, slowd_matype=0)
|
||||
slowk_20_df, slowd_20_df = talib.STOCH(np_high, np_low, np_close, fastk_period=20, slowk_period=12, slowk_matype=0, slowd_period=12, slowd_matype=0)
|
||||
slowk_60_df, slowd_60_df = talib.STOCH(np_high, np_low, np_close, fastk_period=60, slowk_period=37, slowk_matype=0, slowd_period=37, slowd_matype=0)
|
||||
slowk_120_df, slowd_120_df = talib.STOCH(np_high, np_low, np_close, fastk_period=120, slowk_period=74, slowk_matype=0, slowd_period=74, slowd_matype=0)
|
||||
slowk_240_df, slowd_240_df = talib.STOCH(np_high, np_low, np_close, fastk_period=240, slowk_period=148, slowk_matype=0, slowd_period=148, slowd_matype=0)
|
||||
slowk_480_df, slowd_480_df = talib.STOCH(np_high, np_low, np_close, fastk_period=480, slowk_period=296, slowk_matype=0, slowd_period=296, slowd_matype=0)
|
||||
slowk_720_df, slowd_720_df = talib.STOCH(np_high, np_low, np_close, fastk_period=720, slowk_period=445, slowk_matype=0, slowd_period=445, slowd_matype=0)
|
||||
slowk_1440_df, slowd_1440_df = talib.STOCH(np_high, np_low, np_close, fastk_period=1440, slowk_period=890, slowk_matype=0, slowd_period=890, slowd_matype=0)
|
||||
willr = talib.WILLR(np_high, np_low, np_close, timeperiod=11) + 100
|
||||
rsi = talib.RSI(np_close, timeperiod=9)
|
||||
rsi_720 = talib.RSI(np_close, timeperiod=720)
|
||||
rsi_1440 = talib.RSI(np_close, timeperiod=1440)
|
||||
macd, macds, macdo = talib.MACD(np_close, fastperiod=24, slowperiod=52, signalperiod=18)
|
||||
macd_720, macds_720, macdo_720 = talib.MACD(np_close, fastperiod=332, slowperiod=720, signalperiod=250)
|
||||
macd_1440, macds_1440, macdo_1440 = talib.MACD(np_close, fastperiod=665, slowperiod=1440, signalperiod=498)
|
||||
|
||||
"""
|
||||
"""
|
||||
|
||||
df_list = [
|
||||
pd.DataFrame(ymd),
|
||||
pd.DataFrame(open), pd.DataFrame(close), pd.DataFrame(high), pd.DataFrame(low), pd.DataFrame(volume),
|
||||
pd.DataFrame(volume_rate), pd.DataFrame(head_rate), pd.DataFrame(body_rate), pd.DataFrame(tail_rate),
|
||||
pd.DataFrame(open_low_rate), pd.DataFrame(open_high_rate), pd.DataFrame(open_open_rate), pd.DataFrame(open_close_rate), pd.DataFrame(close_low_rate), pd.DataFrame(close_high_rate), pd.DataFrame(close_open_rate), pd.DataFrame(close_close_rate),
|
||||
|
||||
pd.DataFrame(list(support)), pd.DataFrame(list(resistance)),
|
||||
pd.DataFrame(poly_5), pd.DataFrame(poly_10), pd.DataFrame(poly_20), pd.DataFrame(poly_60), pd.DataFrame(poly_120), pd.DataFrame(poly_240), pd.DataFrame(poly_480), pd.DataFrame(poly_720), pd.DataFrame(poly_1440),
|
||||
|
||||
avg5_df, avg10_df, avg20_df, avg60_df, avg120_df, avg240_df, avg480_df, avg720_df, avg1440_df,
|
||||
disparity_avg5_df, disparity_avg20_df, disparity_avg60_df, disparity_avg120_df, disparity_avg240_df, disparity_avg480_df, disparity_avg720_df, disparity_avg1440_df, disparity_avg2880_df,
|
||||
|
||||
pd.DataFrame(new_high_7), pd.DataFrame(new_high_9), pd.DataFrame(new_high_26), pd.DataFrame(new_low_7), pd.DataFrame(new_low_9), pd.DataFrame(new_low_26), pd.DataFrame(high_th),
|
||||
pd.DataFrame(upper_20), pd.DataFrame(lower_20), pd.DataFrame(middle_20), bb_width_df, bb_pb_df, pd.DataFrame(willr),
|
||||
pd.DataFrame(slowk_5_df), pd.DataFrame(slowd_5_df),
|
||||
pd.DataFrame(slowk_10_df), pd.DataFrame(slowd_10_df),
|
||||
pd.DataFrame(slowk_20_df), pd.DataFrame(slowd_20_df),
|
||||
pd.DataFrame(slowk_60_df), pd.DataFrame(slowd_60_df),
|
||||
pd.DataFrame(slowk_120_df), pd.DataFrame(slowd_120_df),
|
||||
pd.DataFrame(slowk_240_df), pd.DataFrame(slowd_240_df),
|
||||
pd.DataFrame(slowk_480_df), pd.DataFrame(slowd_480_df),
|
||||
pd.DataFrame(slowk_720_df), pd.DataFrame(slowd_720_df),
|
||||
pd.DataFrame(slowk_1440_df), pd.DataFrame(slowd_1440_df),
|
||||
pd.DataFrame(rsi), pd.DataFrame(rsi_720), pd.DataFrame(rsi_1440),
|
||||
pd.DataFrame(macd), pd.DataFrame(macds), pd.DataFrame(macdo),
|
||||
pd.DataFrame(macd_720), pd.DataFrame(macds_720), pd.DataFrame(macdo_720),
|
||||
pd.DataFrame(macd_1440), pd.DataFrame(macds_1440), pd.DataFrame(macdo_1440),
|
||||
|
||||
pd.DataFrame(open), pd.DataFrame(close), pd.DataFrame(high), pd.DataFrame(low), pd.DataFrame(volume),
|
||||
|
||||
]
|
||||
|
||||
data = pd.concat(df_list, axis=1)
|
||||
column_names = [
|
||||
'ymd',
|
||||
'open', 'close', 'high', 'low', 'volume',
|
||||
'volume_rate', 'head_rate', 'body_rate', 'tail_rate',
|
||||
'open_low_rate', 'open_high_rate', 'open_open_rate', 'open_close_rate', 'close_low_rate', 'close_high_rate', 'close_open_rate', 'close_close_rate',
|
||||
'support', 'resistance',
|
||||
'poly_5', 'poly_10', 'poly_20', 'poly_60', 'poly_120', 'poly_240', 'poly_480', 'poly_720', 'poly_1440',
|
||||
|
||||
'avg5', 'avg10', 'avg20', 'avg60', 'avg120', 'avg240', 'avg480', 'avg720', 'avg1440',
|
||||
'disparity_avg5', 'disparity_avg20', 'disparity_avg60', 'disparity_avg120', 'disparity_avg240', 'disparity_avg480', 'disparity_avg720', 'disparity_avg1440', 'disparity_avg2880',
|
||||
|
||||
'new_high_7', 'new_high_9', 'new_high_26', 'new_low_7', 'new_low_9', 'new_low_26', 'high_th',
|
||||
'upper_20', 'lower_20', 'middle_20', 'bb_width', 'bb_pb', 'willr',
|
||||
'slowk_5', 'slowd_5',
|
||||
'slowk_10', 'slowd_10',
|
||||
'slowk_20', 'slowd_20',
|
||||
'slowk_60', 'slowd_60',
|
||||
'slowk_120', 'slowd_120',
|
||||
'slowk_240', 'slowd_240',
|
||||
'slowk_480', 'slowd_480',
|
||||
'slowk_720', 'slowd_720',
|
||||
'slowk_1440', 'slowd_1440',
|
||||
'rsi', 'rsi_720', 'rsi_1440',
|
||||
'macd', 'macds', 'macdo',
|
||||
'macd_720', 'macds_720', 'macdo_720',
|
||||
'macd_1440', 'macds_1440', 'macdo_1440',
|
||||
|
||||
'open_raw', 'close_raw', 'high_raw', 'low_raw', 'volume_raw'
|
||||
]
|
||||
data.columns = column_names
|
||||
data.index = pd.DatetimeIndex(ymd)
|
||||
#data = data.dropna(axis=0)
|
||||
return data, len(data)
|
||||
|
||||
def analyze_scale(self, result):
|
||||
result["volume"] = [result["volume"][i] if 0 < result["volume"][i] else 1 for i in range(len(result["volume"]))]
|
||||
# 기본 캔들 정보
|
||||
open_df = pd.DataFrame(result["open"])
|
||||
close_df = pd.DataFrame(result["close"])
|
||||
high_df = pd.DataFrame(result["high"])
|
||||
low_df = pd.DataFrame(result["low"])
|
||||
volume_df = pd.DataFrame(result["volume"])
|
||||
|
||||
# 중복 제거
|
||||
ymd_df = pd.DataFrame(result["ymd"])
|
||||
data_dup = pd.concat([ymd_df, open_df, close_df, high_df, low_df, volume_df], axis=1)
|
||||
data_dup.columns = ["ymd", "open", "close", "high", "low", "volume"]
|
||||
data_dup.index = pd.DatetimeIndex(result["ymd"])
|
||||
data_dup_sorted = data_dup.sort_index(ascending=True)
|
||||
data_dup_sorted = data_dup_sorted.drop_duplicates()
|
||||
|
||||
ymd_df = data_dup_sorted["ymd"]
|
||||
open_df = data_dup_sorted["open"]
|
||||
close_df = data_dup_sorted["close"]
|
||||
high_df = data_dup_sorted["high"]
|
||||
low_df = data_dup_sorted["low"]
|
||||
volume_df = data_dup_sorted["volume"]
|
||||
|
||||
ymd = ymd_df.tolist()
|
||||
open = open_df.tolist()
|
||||
close = close_df.tolist()
|
||||
high = high_df.tolist()
|
||||
low = low_df.tolist()
|
||||
volume = volume_df.tolist()
|
||||
|
||||
open_scaled = (self.scaler.fit_transform(pd.DataFrame(open))).reshape(1,-1)[0]
|
||||
open_scaled = [0.0000000001 if c==0 else c for c in open_scaled]
|
||||
close_scaled = (self.scaler.fit_transform(pd.DataFrame(close))).reshape(1,-1)[0]
|
||||
close_scaled = [0.0000000001 if c == 0 else c for c in close_scaled]
|
||||
high_scaled = (self.scaler.fit_transform(pd.DataFrame(high))).reshape(1,-1)[0]
|
||||
high_scaled = [0.0000000001 if c == 0 else c for c in high_scaled]
|
||||
low_scaled = (self.scaler.fit_transform(pd.DataFrame(low))).reshape(1,-1)[0]
|
||||
low_scaled = [0.0000000001 if c == 0 else c for c in low_scaled]
|
||||
volume_scaled = (self.scaler.fit_transform(pd.DataFrame(volume))).reshape(1, -1)[0]
|
||||
volume_scaled = [0.0000000001 if c == 0 else c for c in volume_scaled]
|
||||
|
||||
volume_rate = np.zeros(len(close))
|
||||
head_rate, body_rate, tail_rate = np.zeros(len(close)), np.zeros(len(close)), np.zeros(len(close))
|
||||
open_low_rate, open_high_rate, open_open_rate, open_close_rate = np.zeros(len(close)), np.zeros(len(close)), np.zeros(len(close)), np.zeros(len(close))
|
||||
close_low_rate, close_high_rate, close_open_rate, close_close_rate = np.zeros(len(close)), np.zeros(len(close)), np.zeros(len(close)), np.zeros(len(close))
|
||||
for i in range(len(close)):
|
||||
length = high_scaled[i] - low_scaled[i]
|
||||
|
||||
if 0 < length:
|
||||
max_value = max(open_scaled[i], close_scaled[i])
|
||||
min_value = min(open_scaled[i], close_scaled[i])
|
||||
|
||||
head_rate[i] = (high_scaled[i] - max_value) / length
|
||||
body_rate[i] = (max_value - min_value) / length
|
||||
tail_rate[i] = (min_value - low_scaled[i]) / length
|
||||
|
||||
if 0 < i:
|
||||
if 0 < volume[i-1]:
|
||||
volume_rate[i] = volume_scaled[i]/volume_scaled[i-1]
|
||||
open_low_rate[i] = (low_scaled[i] - open_scaled[i-1])/open_scaled[i-1]
|
||||
open_high_rate[i] = (high_scaled[i] - open_scaled[i-1])/open_scaled[i-1]
|
||||
open_open_rate[i] = (open_scaled[i] - open_scaled[i-1])/open_scaled[i-1]
|
||||
open_close_rate[i] = (close_scaled[i] - open_scaled[i-1])/open_scaled[i-1]
|
||||
close_low_rate[i] = (low_scaled[i] - close_scaled[i-1])/close_scaled[i-1]
|
||||
close_high_rate[i] = (high_scaled[i] - close_scaled[i-1])/close_scaled[i-1]
|
||||
close_open_rate[i] = (open_scaled[i] - close_scaled[i-1])/close_scaled[i-1]
|
||||
close_close_rate[i] = (close_scaled[i] - close_scaled[i-1])/close_scaled[i-1]
|
||||
|
||||
|
||||
support, resistance = self.get_Support_Resistance(pd.DataFrame(close_scaled))
|
||||
|
||||
#z = np.polyfit(df['speed'], df['dist'], 1) # 기울기와 절편 확인
|
||||
#f = np.poly1d(z) # f(x): f함수
|
||||
if 5 < len(close):
|
||||
poly_5 = [0] * 4 + [np.polyfit(range(5), close[i - 4: i + 1], 1)[0] for i in range(4, len(close))]
|
||||
else:
|
||||
poly_5 = [0] * len(close)
|
||||
if 10 < len(close):
|
||||
poly_10 = [0] * 9 + [np.polyfit(range(10), close[i - 9: i + 1], 1)[0] for i in range(9, len(close))]
|
||||
else:
|
||||
poly_10 = [0] * len(close)
|
||||
if 20 < len(close):
|
||||
poly_20 = [0] * 19 + [np.polyfit(range(20), close[i - 19: i + 1], 1)[0] for i in range(19, len(close))]
|
||||
else:
|
||||
poly_20 = [0] * len(close)
|
||||
if 60 < len(close):
|
||||
poly_60 = [0] * 59 + [np.polyfit(range(60), close[i - 59: i + 1], 1)[0] for i in range(59, len(close))]
|
||||
else:
|
||||
poly_60 = [0] * len(close)
|
||||
if 120 < len(close):
|
||||
poly_120 = [0] * 119 + [np.polyfit(range(120), close[i - 119: i + 1], 1)[0] for i in range(119, len(close))]
|
||||
else:
|
||||
poly_120 = [0] * len(close)
|
||||
if 240 < len(close):
|
||||
poly_240 = [0] * 239 + [np.polyfit(range(240), close[i - 239: i + 1], 1)[0] for i in range(239, len(close))]
|
||||
else:
|
||||
poly_240 = [0] * len(close)
|
||||
if 480 < len(close):
|
||||
poly_480 = [0] * 479 + [np.polyfit(range(480), close[i - 479: i + 1], 1)[0] for i in range(479, len(close))]
|
||||
else:
|
||||
poly_480 = [0] * len(close)
|
||||
if 720 < len(close):
|
||||
poly_720 = [0] * 719 + [np.polyfit(range(720), close[i - 719: i + 1], 1)[0] for i in range(719, len(close))]
|
||||
else:
|
||||
poly_720 = [0] * len(close)
|
||||
if 1440 < len(close):
|
||||
poly_1440 = [0] * 1439 + [np.polyfit(range(1440), close[i - 1439: i + 1], 1)[0] for i in range(1439, len(close))]
|
||||
else:
|
||||
poly_1440 = [0] * len(close)
|
||||
|
||||
# 7일 신고가
|
||||
new_high_7 = [0 for c in range(6)] + [1 if (close_scaled[c - 1] is not None and close_scaled[c] is not None and close_scaled[c - 1] < close_scaled[c]) and None not in close_scaled[c - 6:c + 1] and max(close_scaled[c - 6:c]) < close_scaled[c] else 0 for c in range(6, len(close_scaled))]
|
||||
# 9일 신고가
|
||||
new_high_9 = [0 for c in range(8)] + [1 if (close_scaled[c - 1] is not None and close_scaled[c] is not None and close_scaled[c - 1] < close_scaled[c]) and None not in close_scaled[c - 8:c + 1] and max(close_scaled[c - 8:c]) < close_scaled[c] else 0 for c in range(8, len(close_scaled))]
|
||||
# 26일 신고가
|
||||
new_high_26 = [0 for c in range(25)] + [1 if (close_scaled[c - 1] is not None and close_scaled[c] is not None and close_scaled[c - 1] < close_scaled[c]) and None not in close_scaled[c - 25:c + 1] and max(close_scaled[c - 25:c]) < close_scaled[c] else 0 for c in range(25, len(close_scaled))]
|
||||
|
||||
# 7일 신저가
|
||||
new_low_7 = [0 for c in range(6)] + [1 if (close_scaled[c - 1] is not None and close_scaled[c] is not None and close_scaled[c - 1] < close_scaled[c]) and None not in close_scaled[c - 6:c + 1] and close_scaled[c - 6] < min(close_scaled[c - 6:c + 1]) else 0 for c in range(6, len(close_scaled))]
|
||||
# 9일 신저가
|
||||
new_low_9 = [0 for c in range(8)] + [1 if (close_scaled[c - 1] is not None and close_scaled[c] is not None and close_scaled[c - 1] < close_scaled[c]) and None not in close_scaled[c - 8:c + 1] and close_scaled[c - 8] < min(close_scaled[c - 8:c + 1]) else 0 for c in range(8, len(close_scaled))]
|
||||
# 26일 신저가
|
||||
new_low_26 = [0 for c in range(25)] + [1 if (close_scaled[c - 1] is not None and close_scaled[c] is not None and close_scaled[c - 1] < close_scaled[c]) and None not in close_scaled[c - 25:c + 1] and close_scaled[c - 25] < min(close_scaled[c - 25:c + 1]) else 0 for c in range(25, len(close_scaled))]
|
||||
|
||||
high_th = [0]
|
||||
for i in range(1, len(close_scaled)):
|
||||
count = 0
|
||||
for c in range(i-1,i-30,-1):
|
||||
if c < 0:
|
||||
break
|
||||
if close_scaled[i] < close_scaled[c]:
|
||||
break
|
||||
else:
|
||||
count += 1
|
||||
high_th.append(count)
|
||||
|
||||
# 이동 평균
|
||||
close_df = pd.DataFrame(close_scaled)
|
||||
|
||||
avg5_df = close_df.ewm(5).mean()
|
||||
avg10_df = close_df.ewm(10).mean()
|
||||
avg20_df = close_df.ewm(20).mean()
|
||||
avg60_df = close_df.ewm(60).mean()
|
||||
avg120_df = close_df.ewm(120).mean()
|
||||
avg240_df = close_df.ewm(240).mean()
|
||||
avg480_df = close_df.ewm(480).mean()
|
||||
avg720_df = close_df.ewm(720).mean()
|
||||
avg1440_df = close_df.ewm(1440).mean()
|
||||
|
||||
# 이격도
|
||||
disparity_avg5_df = (close_df / close_df.ewm(span=5, min_periods=5, adjust=False).mean())
|
||||
disparity_avg5_df = disparity_avg5_df.replace({None: np.nan})
|
||||
disparity_avg20_df = (close_df / close_df.ewm(span=20, min_periods=20, adjust=False).mean())
|
||||
disparity_avg20_df = disparity_avg20_df.replace({None: np.nan})
|
||||
disparity_avg60_df = (close_df / close_df.ewm(span=60, min_periods=60, adjust=False).mean())
|
||||
disparity_avg60_df = disparity_avg60_df.replace({None: np.nan})
|
||||
disparity_avg120_df = (close_df / close_df.ewm(span=120, min_periods=120, adjust=False).mean())
|
||||
disparity_avg120_df = disparity_avg120_df.replace({None: np.nan})
|
||||
disparity_avg240_df = (close_df / close_df.ewm(span=240, min_periods=240, adjust=False).mean())
|
||||
disparity_avg240_df = disparity_avg240_df.replace({None: np.nan})
|
||||
disparity_avg480_df = (close_df / close_df.ewm(span=480, min_periods=480, adjust=False).mean())
|
||||
disparity_avg480_df = disparity_avg480_df.replace({None: np.nan})
|
||||
disparity_avg720_df = (close_df / close_df.ewm(span=720, min_periods=720, adjust=False).mean())
|
||||
disparity_avg720_df = disparity_avg720_df.replace({None: np.nan})
|
||||
disparity_avg1440_df = (close_df / close_df.ewm(span=1440, min_periods=1440, adjust=False).mean())
|
||||
disparity_avg1440_df = disparity_avg1440_df.replace({None: np.nan})
|
||||
disparity_avg2880_df = (close_df / close_df.ewm(span=2880, min_periods=2880, adjust=False).mean())
|
||||
disparity_avg2880_df = disparity_avg2880_df.replace({None: np.nan})
|
||||
|
||||
disparity_avg5_list = list(disparity_avg5_df.values.reshape(-1))
|
||||
disparity_avg20_list = list(disparity_avg20_df.values.reshape(-1))
|
||||
disparity_avg60_list = list(disparity_avg60_df.values.reshape(-1))
|
||||
disparity_avg120_list = list(disparity_avg120_df.values.reshape(-1))
|
||||
disparity_avg240_list = list(disparity_avg240_df.values.reshape(-1))
|
||||
disparity_avg480_list = list(disparity_avg480_df.values.reshape(-1))
|
||||
disparity_avg720_list = list(disparity_avg720_df.values.reshape(-1))
|
||||
disparity_avg1440_list = list(disparity_avg1440_df.values.reshape(-1))
|
||||
|
||||
disparity_diff_20_5, disparity_diff_20_5_rate = self.getDiff_Rate(disparity_avg20_list, disparity_avg5_list, duration=20)
|
||||
disparity_diff_60_20, disparity_diff_60_20_rate = self.getDiff_Rate(disparity_avg60_list, disparity_avg20_list, duration=60)
|
||||
disparity_diff_120_20, disparity_diff_120_20_rate = self.getDiff_Rate(disparity_avg120_list, disparity_avg20_list, duration=120)
|
||||
disparity_diff_240_20, disparity_diff_240_20_rate = self.getDiff_Rate(disparity_avg240_list, disparity_avg20_list, duration=240)
|
||||
disparity_diff_480_20, disparity_diff_480_20_rate = self.getDiff_Rate(disparity_avg480_list, disparity_avg20_list, duration=480)
|
||||
disparity_diff_720_20, disparity_diff_720_20_rate = self.getDiff_Rate(disparity_avg720_list, disparity_avg20_list, duration=720)
|
||||
disparity_diff_1440_20, disparity_diff_1440_20_rate = self.getDiff_Rate(disparity_avg1440_list, disparity_avg20_list, duration=1440)
|
||||
|
||||
|
||||
""""""
|
||||
n, t = 20, 2
|
||||
max_20 = close_df.rolling(window=n).mean()
|
||||
stddev_20 = close_df.rolling(window=n).std()
|
||||
upper_20 = max_20 + (stddev_20 * t) # 상단 볼리저 밴드
|
||||
lower_20 = max_20 - (stddev_20 * t) # 하단 볼리저 밴드
|
||||
middle_20 = (upper_20 + lower_20) / 2
|
||||
|
||||
width_df = (upper_20 - lower_20) / middle_20
|
||||
width_min = np.min(width_df[0])
|
||||
width_max = np.max(width_df[0])
|
||||
bb_width_df = 100 * (width_df - width_min) / (width_max - width_min)
|
||||
bb_pb_df = 100 * (close_df - lower_20) / (upper_20 - lower_20)
|
||||
|
||||
upper_20 = list(np.reshape(upper_20.values, -1))
|
||||
lower_20 = list(np.reshape(lower_20.values, -1))
|
||||
middle_20 = list(np.reshape(middle_20.values, -1))
|
||||
|
||||
np_high, np_low, np_close = np.array(high_scaled, dtype=np.float64), np.array(low_scaled, dtype=np.float64), np.array(close_scaled, dtype=np.float64)
|
||||
slowk_5_df, slowd_5_df = talib.STOCH(np_high, np_low, np_close, fastk_period=5, slowk_period=3, slowk_matype=0, slowd_period=3, slowd_matype=0)
|
||||
slowk_10_df, slowd_10_df = talib.STOCH(np_high, np_low, np_close, fastk_period=10, slowk_period=6, slowk_matype=0, slowd_period=6, slowd_matype=0)
|
||||
slowk_20_df, slowd_20_df = talib.STOCH(np_high, np_low, np_close, fastk_period=20, slowk_period=12, slowk_matype=0, slowd_period=12, slowd_matype=0)
|
||||
slowk_60_df, slowd_60_df = talib.STOCH(np_high, np_low, np_close, fastk_period=60, slowk_period=37, slowk_matype=0, slowd_period=37, slowd_matype=0)
|
||||
slowk_120_df, slowd_120_df = talib.STOCH(np_high, np_low, np_close, fastk_period=120, slowk_period=74, slowk_matype=0, slowd_period=74, slowd_matype=0)
|
||||
slowk_240_df, slowd_240_df = talib.STOCH(np_high, np_low, np_close, fastk_period=240, slowk_period=148, slowk_matype=0, slowd_period=148, slowd_matype=0)
|
||||
slowk_480_df, slowd_480_df = talib.STOCH(np_high, np_low, np_close, fastk_period=480, slowk_period=296, slowk_matype=0, slowd_period=296, slowd_matype=0)
|
||||
slowk_720_df, slowd_720_df = talib.STOCH(np_high, np_low, np_close, fastk_period=720, slowk_period=445, slowk_matype=0, slowd_period=445, slowd_matype=0)
|
||||
slowk_1440_df, slowd_1440_df = talib.STOCH(np_high, np_low, np_close, fastk_period=1440, slowk_period=890, slowk_matype=0, slowd_period=890, slowd_matype=0)
|
||||
willr = talib.WILLR(np_high, np_low, np_close, timeperiod=11) + 100
|
||||
rsi = talib.RSI(np_close, timeperiod=9)
|
||||
rsi_720 = talib.RSI(np_close, timeperiod=720)
|
||||
rsi_1440 = talib.RSI(np_close, timeperiod=1440)
|
||||
macd, macds, macdo = talib.MACD(np_close, fastperiod=24, slowperiod=52, signalperiod=18)
|
||||
macd_720, macds_720, macdo_720 = talib.MACD(np_close, fastperiod=332, slowperiod=720, signalperiod=250)
|
||||
macd_1440, macds_1440, macdo_1440 = talib.MACD(np_close, fastperiod=665, slowperiod=1440, signalperiod=498)
|
||||
|
||||
"""
|
||||
"""
|
||||
|
||||
df_list = [
|
||||
pd.DataFrame(ymd),
|
||||
pd.DataFrame(open_scaled), pd.DataFrame(close_scaled), pd.DataFrame(high_scaled), pd.DataFrame(low_scaled), pd.DataFrame(volume_scaled),
|
||||
pd.DataFrame(volume_rate), pd.DataFrame(head_rate), pd.DataFrame(body_rate), pd.DataFrame(tail_rate),
|
||||
pd.DataFrame(open_low_rate), pd.DataFrame(open_high_rate), pd.DataFrame(open_open_rate), pd.DataFrame(open_close_rate), pd.DataFrame(close_low_rate), pd.DataFrame(close_high_rate), pd.DataFrame(close_open_rate), pd.DataFrame(close_close_rate),
|
||||
|
||||
pd.DataFrame(list(support)), pd.DataFrame(list(resistance)),
|
||||
pd.DataFrame(poly_5), pd.DataFrame(poly_10), pd.DataFrame(poly_20), pd.DataFrame(poly_60), pd.DataFrame(poly_120), pd.DataFrame(poly_240), pd.DataFrame(poly_480), pd.DataFrame(poly_720), pd.DataFrame(poly_1440),
|
||||
|
||||
avg5_df, avg10_df, avg20_df, avg60_df, avg120_df, avg240_df, avg480_df, avg720_df, avg1440_df,
|
||||
disparity_avg5_df, disparity_avg20_df, disparity_avg60_df, disparity_avg120_df, disparity_avg240_df, disparity_avg480_df, disparity_avg720_df, disparity_avg1440_df, disparity_avg2880_df,
|
||||
pd.DataFrame(disparity_diff_20_5), pd.DataFrame(disparity_diff_20_5_rate),
|
||||
pd.DataFrame(disparity_diff_60_20), pd.DataFrame(disparity_diff_60_20_rate),
|
||||
pd.DataFrame(disparity_diff_120_20), pd.DataFrame(disparity_diff_120_20_rate),
|
||||
pd.DataFrame(disparity_diff_240_20), pd.DataFrame(disparity_diff_240_20_rate),
|
||||
pd.DataFrame(disparity_diff_480_20), pd.DataFrame(disparity_diff_480_20_rate),
|
||||
pd.DataFrame(disparity_diff_720_20), pd.DataFrame(disparity_diff_720_20_rate),
|
||||
pd.DataFrame(disparity_diff_1440_20), pd.DataFrame(disparity_diff_1440_20_rate),
|
||||
|
||||
pd.DataFrame(new_high_7), pd.DataFrame(new_high_9), pd.DataFrame(new_high_26), pd.DataFrame(new_low_7), pd.DataFrame(new_low_9), pd.DataFrame(new_low_26), pd.DataFrame(high_th),
|
||||
pd.DataFrame(upper_20), pd.DataFrame(lower_20), pd.DataFrame(middle_20), bb_width_df, bb_pb_df, pd.DataFrame(willr),
|
||||
pd.DataFrame(slowk_5_df), pd.DataFrame(slowd_5_df),
|
||||
pd.DataFrame(slowk_10_df), pd.DataFrame(slowd_10_df),
|
||||
pd.DataFrame(slowk_20_df), pd.DataFrame(slowd_20_df),
|
||||
pd.DataFrame(slowk_60_df), pd.DataFrame(slowd_60_df),
|
||||
pd.DataFrame(slowk_120_df), pd.DataFrame(slowd_120_df),
|
||||
pd.DataFrame(slowk_240_df), pd.DataFrame(slowd_240_df),
|
||||
pd.DataFrame(slowk_480_df), pd.DataFrame(slowd_480_df),
|
||||
pd.DataFrame(slowk_720_df), pd.DataFrame(slowd_720_df),
|
||||
pd.DataFrame(slowk_1440_df), pd.DataFrame(slowd_1440_df),
|
||||
pd.DataFrame(rsi), pd.DataFrame(rsi_720), pd.DataFrame(rsi_1440),
|
||||
pd.DataFrame(macd), pd.DataFrame(macds), pd.DataFrame(macdo),
|
||||
pd.DataFrame(macd_720), pd.DataFrame(macds_720), pd.DataFrame(macdo_720),
|
||||
pd.DataFrame(macd_1440), pd.DataFrame(macds_1440), pd.DataFrame(macdo_1440),
|
||||
|
||||
pd.DataFrame(open), pd.DataFrame(close), pd.DataFrame(high), pd.DataFrame(low), pd.DataFrame(volume)
|
||||
]
|
||||
|
||||
data = pd.concat(df_list, axis=1)
|
||||
column_names = [
|
||||
'ymd',
|
||||
'open', 'close', 'high', 'low', 'volume',
|
||||
'volume_rate', 'head_rate', 'body_rate', 'tail_rate',
|
||||
'open_low_rate', 'open_high_rate', 'open_open_rate', 'open_close_rate', 'close_low_rate', 'close_high_rate', 'close_open_rate', 'close_close_rate',
|
||||
|
||||
'support', 'resistance',
|
||||
'poly_5', 'poly_10', 'poly_20', 'poly_60', 'poly_120', 'poly_240', 'poly_480', 'poly_720', 'poly_1440',
|
||||
|
||||
'avg5', 'avg10', 'avg20', 'avg60', 'avg120', 'avg240', 'avg480', 'avg720', 'avg1440',
|
||||
'disparity_avg5', 'disparity_avg20', 'disparity_avg60', 'disparity_avg120', 'disparity_avg240', 'disparity_avg480', 'disparity_avg720', 'disparity_avg1440', 'disparity_avg2880',
|
||||
'disparity_diff_20_5', 'disparity_diff_20_5_rate',
|
||||
'disparity_diff_60_20', 'disparity_diff_60_20_rate',
|
||||
'disparity_diff_120_20', 'disparity_diff_120_20_rate',
|
||||
'disparity_diff_240_20', 'disparity_diff_240_20_rate',
|
||||
'disparity_diff_480_20', 'disparity_diff_480_20_rate',
|
||||
'disparity_diff_720_20', 'disparity_diff_720_20_rate',
|
||||
'disparity_diff_1440_20', 'disparity_diff_1440_20_rate',
|
||||
|
||||
'new_high_7', 'new_high_9', 'new_high_26', 'new_low_7', 'new_low_9', 'new_low_26', 'high_th',
|
||||
'upper_20', 'lower_20', 'middle_20', 'bb_width', 'bb_pb', 'willr',
|
||||
'slowk_5', 'slowd_5',
|
||||
'slowk_10', 'slowd_10',
|
||||
'slowk_20', 'slowd_20',
|
||||
'slowk_60', 'slowd_60',
|
||||
'slowk_120', 'slowd_120',
|
||||
'slowk_240', 'slowd_240',
|
||||
'slowk_480', 'slowd_480',
|
||||
'slowk_720', 'slowd_720',
|
||||
'slowk_1440', 'slowd_1440',
|
||||
'rsi', 'rsi_720', 'rsi_1440',
|
||||
'macd', 'macds', 'macdo',
|
||||
'macd_720', 'macds_720', 'macdo_720',
|
||||
'macd_1440', 'macds_1440', 'macdo_1440',
|
||||
|
||||
'open_raw', 'close_raw', 'high_raw', 'low_raw', 'volume_raw'
|
||||
]
|
||||
data.columns = column_names
|
||||
data.index = pd.DatetimeIndex(ymd)
|
||||
#data = data.dropna(axis=0)
|
||||
return data, len(data)
|
||||
|
||||
def getData(self, ticker, mins=None, ymd=None, get_days=14):
|
||||
if ymd is None:
|
||||
result = self.getCoinData(ticker, mins=mins, get_days=get_days)
|
||||
else:
|
||||
result = self.getCoinData(ticker, mins=mins, ymd=ymd, get_days=get_days)
|
||||
|
||||
if len(result['ymd']) < 1:
|
||||
return None, None, None
|
||||
|
||||
#result_tic = self.makeTickData(result_m1, mins=minute)
|
||||
data_scale, ci = self.analyze_scale(result)
|
||||
data, ci = self.analyze_raw(result)
|
||||
|
||||
ticker['disparity_low_min'] = self.getDisparity_low_min(ticker, min='minutely')
|
||||
|
||||
return data, data_scale, ci
|
||||
130
LabelMaker.py
130
LabelMaker.py
@@ -1,130 +0,0 @@
|
||||
import os
|
||||
import logging
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
from stock.util.LabelChecker import LabelChecker
|
||||
|
||||
class LabelMaker:
|
||||
db_filename = None
|
||||
labelChecker = None
|
||||
|
||||
def __init__(self, RESOURCE_PATH):
|
||||
self.labelChecker = LabelChecker(RESOURCE_PATH)
|
||||
self.db_filename = os.path.join(RESOURCE_PATH, "hts.db")
|
||||
return
|
||||
|
||||
def clearLabel(self, stock_code, ymd):
|
||||
self.labelChecker.clearLabel(self.db_filename, stock_code, ymd)
|
||||
return
|
||||
|
||||
def showLabels(self, stock_code, ymd):
|
||||
self.labelChecker.showLabels(stock_code, ymd)
|
||||
return
|
||||
|
||||
def update(self, stock_code, ymd, hms, label):
|
||||
self.labelChecker.makeLabel(self.db_filename, stock_code, ymd, hms, label)
|
||||
return
|
||||
|
||||
def write(self, stock_code, ymd, outFp):
|
||||
logging.info(stock_code + " / " + ymd)
|
||||
self.labelChecker.showLabels(stock_code, ymd, outFp)
|
||||
return
|
||||
|
||||
def check(self, stock_codes):
|
||||
# 종목에 대해서 주어진 일자에 대해서 통계치 추출하기
|
||||
for stock_code in stock_codes:
|
||||
ymds = self.labelChecker.getDate(stock_code)
|
||||
for ymd in ymds:
|
||||
logging.info(stock_code + " / " + ymd)
|
||||
bsLine, data = self.labelChecker.makeCandidate(stock_code, ymd)
|
||||
self.labelChecker.updateLabel(self.db_filename, stock_code, bsLine, data, ymd)
|
||||
return
|
||||
|
||||
if __name__ == "__main__":
|
||||
PROJECT_HOME = os.path.join(os.path.dirname(__file__))
|
||||
RESOURCE_PATH = os.path.join(PROJECT_HOME, "resources")
|
||||
|
||||
labelMaker = LabelMaker(RESOURCE_PATH)
|
||||
|
||||
|
||||
MODE = "WRITE"
|
||||
if MODE == "UPDATE":
|
||||
# 매일 입력하면서 정답 셋 만들기
|
||||
stock_code = "252670"
|
||||
ymd = '20220531'
|
||||
|
||||
labelMaker.clearLabel(stock_code, ymd)
|
||||
|
||||
labelMaker.update(stock_code, ymd, "0901", 2)
|
||||
labelMaker.update(stock_code, ymd, "0902", 2)
|
||||
labelMaker.update(stock_code, ymd, "0903", 2)
|
||||
labelMaker.update(stock_code, ymd, "1429", 2)
|
||||
labelMaker.update(stock_code, ymd, "1430", 2)
|
||||
labelMaker.update(stock_code, ymd, "1431", 2)
|
||||
labelMaker.update(stock_code, ymd, "1432", 2)
|
||||
labelMaker.update(stock_code, ymd, "1433", 2)
|
||||
labelMaker.update(stock_code, ymd, "1434", 2)
|
||||
labelMaker.update(stock_code, ymd, "1435", 2)
|
||||
labelMaker.update(stock_code, ymd, "1436", 2)
|
||||
labelMaker.update(stock_code, ymd, "1437", 2)
|
||||
labelMaker.update(stock_code, ymd, "1438", 2)
|
||||
labelMaker.update(stock_code, ymd, "1439", 2)
|
||||
labelMaker.update(stock_code, ymd, "1440", 2)
|
||||
labelMaker.update(stock_code, ymd, "1441", 2)
|
||||
labelMaker.update(stock_code, ymd, "1442", 2)
|
||||
labelMaker.update(stock_code, ymd, "1443", 2)
|
||||
labelMaker.update(stock_code, ymd, "1444", 2)
|
||||
labelMaker.update(stock_code, ymd, "1445", 2)
|
||||
labelMaker.update(stock_code, ymd, "1446", 2)
|
||||
labelMaker.update(stock_code, ymd, "1447", 2)
|
||||
|
||||
labelMaker.update(stock_code, ymd, "0930", 1)
|
||||
labelMaker.update(stock_code, ymd, "0931", 1)
|
||||
labelMaker.update(stock_code, ymd, "0932", 1)
|
||||
labelMaker.update(stock_code, ymd, "0933", 1)
|
||||
labelMaker.update(stock_code, ymd, "0934", 1)
|
||||
labelMaker.update(stock_code, ymd, "0935", 1)
|
||||
labelMaker.update(stock_code, ymd, "1516", 1)
|
||||
labelMaker.update(stock_code, ymd, "1517", 1)
|
||||
labelMaker.update(stock_code, ymd, "1518", 1)
|
||||
labelMaker.update(stock_code, ymd, "1519", 1)
|
||||
|
||||
|
||||
labelMaker.showLabels(stock_code, ymd)
|
||||
|
||||
else:
|
||||
stock_codes = {
|
||||
"252670": [
|
||||
'20220502', '20220503', '20220504', '20220506', '20220509',
|
||||
'20220510', '20220511', '20220512', '20220513', '20220516',
|
||||
'20220517', '20220518', '20220519', '20220520', '20220523',
|
||||
'20220524', '20220525', '20220526', '20220527', '20220530',
|
||||
'20220531', '20220602', '20220603', '20220607', '20220608',
|
||||
'20220609', '20220610', '20220613', '20220614', '20220615',
|
||||
'20220616', '20220617', '20220620', '20220621', '20220622',
|
||||
'20220623', '20220624', '20220627', '20220628', '20220629',
|
||||
'20220630', '20220624', '20220627', '20220628', '20220629',
|
||||
'20220701', '20220704', '20220705', '20220706', '20220707',
|
||||
'20220708', '20220711', '20220712', '20220713', '20220714',
|
||||
'20220715', '20220718', '20220719', '20220720', '20220721',
|
||||
'20220722', '20220725', '20220726', '20220727', '20220728',
|
||||
'20220729', '20220801', '20220802', '20220803', '20220804',
|
||||
'20220805', '20220808', '20220809', '20220810', '20220811',
|
||||
'20220812', '20220816', '20220817', '20220818', '20220819'],
|
||||
"122630": ['20220701', '20220704', '20220705', '20220706', '20220707',
|
||||
'20220708', '20220711', '20220712', '20220713', '20220714',
|
||||
'20220715', '20220718', '20220719', '20220720', '20220721',
|
||||
'20220722', '20220725', '20220726', '20220727', '20220728',
|
||||
'20220729', '20220801', '20220802', '20220803', '20220804',
|
||||
'20220805', '20220808', '20220809', '20220810', '20220811',
|
||||
'20220812', '20220816', '20220817'],
|
||||
}
|
||||
|
||||
if MODE == "WRITE":
|
||||
for stock_code in stock_codes:
|
||||
fileName = os.path.join(RESOURCE_PATH, "tmp", "check_"+stock_code+".txt")
|
||||
outFp = open(fileName, "w")
|
||||
for ymd in stock_codes[stock_code]:
|
||||
labelMaker.write(stock_code, ymd, outFp)
|
||||
outFp.close()
|
||||
else:
|
||||
labelMaker.check(stock_codes)
|
||||
273
Simulation.py
273
Simulation.py
@@ -1,273 +0,0 @@
|
||||
from math import nan
|
||||
import pandas as pd
|
||||
import plotly.graph_objects as go
|
||||
from plotly import subplots
|
||||
import os
|
||||
import sqlite3
|
||||
|
||||
from hts.HTS import HTS
|
||||
from stock.util.Stock2Vector import Stock2Vector
|
||||
from stock.util.LabelChecker import LabelChecker
|
||||
|
||||
from hts.BuySellChecker import BuySellChecker
|
||||
|
||||
class Simulation (HTS):
|
||||
stock2Vector = None
|
||||
buySellChecker = None
|
||||
|
||||
def __init__(self, RESOURCE_PATH):
|
||||
super().__init__(RESOURCE_PATH)
|
||||
|
||||
self.RESOURCE_PATH = RESOURCE_PATH
|
||||
|
||||
self.buySellChecker = BuySellChecker()
|
||||
|
||||
try:
|
||||
self.stock2Vector = Stock2Vector(RESOURCE_PATH)
|
||||
self.labelChecker = LabelChecker(RESOURCE_PATH)
|
||||
except:
|
||||
pass
|
||||
#self.connect()
|
||||
return
|
||||
|
||||
def draw(self, stock_code, given_day, data, bsLine):
|
||||
if bsLine is None:
|
||||
return
|
||||
|
||||
# 어제 데이터는 지운다.
|
||||
data = data.loc[pd.DatetimeIndex(data.index).day == int(given_day[6:])]
|
||||
buy_line = bsLine['buy'][len(bsLine['buy'])-len(data):]
|
||||
buy_weight_line = bsLine['buy_weight'][len(bsLine['buy'])-len(data):]
|
||||
sell_line = bsLine['sell'][len(bsLine['buy'])-len(data):]
|
||||
|
||||
# 그래프 설정을 위한 변수를 생성한다.
|
||||
data = data.astype({'open': 'int', 'high': 'int', 'low': 'int', 'close': 'int', 'volume': 'int',
|
||||
'avg5': 'float', 'avg20': 'float', 'avg60': 'float', 'avg120': 'float', 'avg200': 'float',
|
||||
'disparity_avg5': 'float', 'disparity_avg20': 'float', 'disparity_avg60': 'float', 'disparity_avg120': 'float', 'disparity_avg200': 'float',
|
||||
'fast_k': 'float', 'slow_k': 'float', 'slow_d': 'float',
|
||||
'macd': 'float', 'macds': 'float', 'macdo': 'float',
|
||||
'rsi': 'float', 'rsis': 'float'
|
||||
})
|
||||
|
||||
buy_size = []
|
||||
buy_colors = []
|
||||
for i in range(len(buy_line)):
|
||||
if buy_line[i] < 0:
|
||||
buy_colors.append("#ffffff")
|
||||
buy_line[i] = nan
|
||||
buy_size.append(0)
|
||||
else:
|
||||
buy_colors.append("#0C752E")
|
||||
buy_size.append(10 + (5 * buy_weight_line[i]))
|
||||
|
||||
sell_colors = []
|
||||
for i in range(len(sell_line)):
|
||||
if sell_line[i] < 0:
|
||||
sell_colors.append("#ffffff")
|
||||
sell_line[i] = nan
|
||||
else:
|
||||
sell_colors.append("#00ced1")
|
||||
|
||||
volume_colors = []
|
||||
for i in range(len(buy_line)):
|
||||
if data['open'][i] > data['close'][i]:
|
||||
volume_colors.append("#0000FF")
|
||||
elif data['open'][i] < data['close'][i]:
|
||||
volume_colors.append("#FF0000")
|
||||
else:
|
||||
volume_colors.append("#000000")
|
||||
|
||||
# 그래프를 설정한다.
|
||||
buy_check = go.Scatter(x=data['date'], y=buy_line, mode='markers', name="buy", marker=dict(size=buy_size, color=buy_colors, line_width=0))
|
||||
sell_check = go.Scatter(x=data['date'], y=sell_line, mode='markers', name="sell", marker=dict(size=14, color=sell_colors, line_width=0))
|
||||
|
||||
#volume_line = go.Scatter(x=data['date'], y=data["volume"], mode='lines', name='volume')
|
||||
volume_line = go.Bar(x=data['date'], y=data["volume"], marker_color=volume_colors, name='volume')
|
||||
|
||||
disparity_avg5 = go.Scatter(x=data['date'], y=data["disparity_avg5"], name="disparity_avg5", line_color='#F81191')
|
||||
disparity_avg20 = go.Scatter(x=data['date'], y=data["disparity_avg20"], name="disparity_avg20", line_color='#097F19')
|
||||
disparity_avg30 = go.Scatter(x=data['date'], y=data["disparity_avg30"], name="disparity_avg30", line_color='#097F19')
|
||||
disparity_avg60 = go.Scatter(x=data['date'], y=data["disparity_avg60"], name="disparity_avg60", line_color='#671BEA')
|
||||
disparity_avg120 = go.Scatter(x=data['date'], y=data["disparity_avg120"], name="disparity_avg120", line_color='#DFB809')
|
||||
disparity_avg200 = go.Scatter(x=data['date'], y=data["disparity_avg200"], name="disparity_avg200", line_color='#000000')
|
||||
|
||||
macd_line = go.Scatter(x=data['date'], y=data["macd"], line=dict(color='red', width=2), name='macd')
|
||||
macd_s_line = go.Scatter(x=data['date'], y=data["macds"], line=dict(dash='dashdot', color='black', width=2), name='macds')
|
||||
macd_o_line = go.Bar(x=data['date'], y=data["macdo"], marker_color='purple', name='macdo')
|
||||
|
||||
# fast_k_line = go.Scatter(x=hts['date'], y=hts["fast_k"], mode='lines', name='fast_k')
|
||||
slow_k_line = go.Scatter(x=data['date'], y=data["slow_k"], line=dict(color='red', width=2), name='slow_k')
|
||||
slow_d_line = go.Scatter(x=data['date'], y=data["slow_d"], line=dict(dash='dashdot', color='black', width=2), name='slow_d')
|
||||
|
||||
rsi_line = go.Scatter(x=data['date'], y=data["rsi"], line=dict(color='red', width=2), name='rsi')
|
||||
rsis_line = go.Scatter(x=data['date'], y=data["rsis"], line=dict(dash='dashdot', color='black', width=2), name='rsis')
|
||||
|
||||
upper = go.Scatter(x=data['date'], y=data["upper"], name="upper", line_color='#000000')
|
||||
lower = go.Scatter(x=data['date'], y=data["lower"], name="lower", line_color='#000000')
|
||||
|
||||
avg5 = go.Scatter(x=data['date'], y=data["avg5"], name="avg5", line_color='#F81191')
|
||||
avg20 = go.Scatter(x=data['date'], y=data["avg20"], name="avg20", line_color='#097F19')
|
||||
avg30 = go.Scatter(x=data['date'], y=data["avg30"], name="avg30", line_color='#097F19')
|
||||
avg60 = go.Scatter(x=data['date'], y=data["avg60"], name="avg60", line_color='#671BEA')
|
||||
avg120 = go.Scatter(x=data['date'], y=data["avg120"], name="avg120", line_color='#DFB809')
|
||||
avg200 = go.Scatter(x=data['date'], y=data["avg200"], name="avg200", line_color='#000000')
|
||||
|
||||
changeLine = go.Scatter(x=data['date'], y=data["changeLine"], name='changeLine', line_color='#14A200') #CF6E0D
|
||||
baseLine = go.Scatter(x=data['date'], y=data["baseLine"], name='baseLine', line_color='orange')
|
||||
laggingSpan = go.Scatter(x=data['date'], y=data["laggingSpan"], name='laggingSpan', line_color='#B50ABB')
|
||||
leadingSpan1 = go.Scatter(x=data['date'], y=data["leadingSpan1"], name='leadingSpan1', line_color='black')
|
||||
leadingSpan2 = go.Scatter(x=data['date'], y=data["leadingSpan2"], name='leadingSpan2', line_color='black')
|
||||
|
||||
text_list = []
|
||||
for i in range(len(data['macd'])):
|
||||
text = "{}<br><br>open: {}<br>close: {}<br>high: {}<br>low: {}<br>volume: {}<br><br>avg5: {:.2f}<br>avg20: {:.2f}<br>avg60: {:.2f}<br>avg200: {:.2f}<br><br>d_avg5: {:.6f}<br>d_avg20: {:.6f}<br>d_avg60: {:.6f}<br>d_avg200: {:.6f}<br>d_avg5_60: {:.6f}<br>d_avg5_200: {:.6f}<br>d_avg200-5: {:.6f}<br><br>macd: {:.2f}<br>slow_k: {:.2f}<br>rsi: {:.2f}".format(
|
||||
data['date'][i],
|
||||
data['open'][i],data['close'][i],data['high'][i],data['low'][i],data['volume'][i],
|
||||
data['avg5'][i],data['avg20'][i],data['avg60'][i],data['avg200'][i],
|
||||
data['disparity_avg5'][i], data['disparity_avg20'][i], data['disparity_avg60'][i], data['disparity_avg200'][i],
|
||||
max(data['disparity_avg5'][i], data['disparity_avg20'][i], data['disparity_avg60'][i]) - min(data['disparity_avg5'][i], data['disparity_avg20'][i], data['disparity_avg60'][i]),
|
||||
max(data['disparity_avg5'][i], data['disparity_avg20'][i], data['disparity_avg60'][i], data['disparity_avg200'][i]) - min(data['disparity_avg5'][i], data['disparity_avg20'][i], data['disparity_avg60'][i], data['disparity_avg200'][i]),
|
||||
abs(data['disparity_avg200'][i] - data['disparity_avg5'][i]),
|
||||
data['macd'][i],data['slow_k'][i],data['rsi'][i]
|
||||
)
|
||||
text_list.append(text)
|
||||
|
||||
candle_stick = go.Candlestick(x=data['date'],
|
||||
open=data['open'],
|
||||
high=data['high'],
|
||||
low=data['low'],
|
||||
close=data['close'],
|
||||
increasing_line_color='red',
|
||||
decreasing_line_color='blue',
|
||||
showlegend=False,
|
||||
text=text_list,
|
||||
hoverinfo="text"
|
||||
)
|
||||
|
||||
# candle_data = [avg5, avg20, avg30, avg60, avg120, avg200, buy_check, sell_check, laggingSpan, changeLine, baseLine, upper, lower, candle_stick]
|
||||
# candle_data = [avg5, avg20, avg30, avg60, avg200, buy_check, sell_check, upper, lower, candle_stick]
|
||||
# candle_data = [buy_check, sell_check, changeLine, baseLine, changeLine, laggingSpan, candle_stick]
|
||||
candle_data = [avg5, avg200, buy_check, sell_check, candle_stick]
|
||||
|
||||
volume_data = [volume_line]
|
||||
disparity_data = [disparity_avg5, disparity_avg20, disparity_avg30, disparity_avg60, disparity_avg120, disparity_avg200]
|
||||
macd_data = [macd_line, macd_s_line, macd_o_line]
|
||||
stochastic_data = [slow_k_line, slow_d_line]
|
||||
rsi_data = [rsi_line, rsis_line]
|
||||
|
||||
# 그래프를 그린다.
|
||||
"""
|
||||
fig = go.Figure(data=candle_data)
|
||||
fig.update_layout(title=stock_code + "_" + given_day)
|
||||
fig.show()
|
||||
"""
|
||||
|
||||
fig = subplots.make_subplots(
|
||||
rows=6, cols=1,
|
||||
subplot_titles=("거래량", "이격도", "스토캐스틱", "RSI", "MACD", '캔들'),
|
||||
#specs=[[{}], [{}], [{}], [{}], [{}], [{}]],
|
||||
shared_xaxes=True, horizontal_spacing=0.03, vertical_spacing=0.01,
|
||||
row_heights=[200, 200, 200, 200, 200, 700]
|
||||
)
|
||||
for trace in volume_data:
|
||||
fig.append_trace(trace, 1, 1)
|
||||
for trace in disparity_data:
|
||||
fig.append_trace(trace, 2, 1)
|
||||
for trace in stochastic_data:
|
||||
fig.append_trace(trace, 3, 1)
|
||||
for trace in rsi_data:
|
||||
fig.append_trace(trace, 4, 1)
|
||||
for trace in macd_data:
|
||||
fig.append_trace(trace, 5, 1)
|
||||
for trace in candle_data:
|
||||
fig.append_trace(trace, 6, 1)
|
||||
|
||||
#fig.update_xaxes(nticks=5)
|
||||
#fig.update_layout(height=1800, title=stock_code + "_" + given_day, xaxis_rangeslider_visible=False)
|
||||
|
||||
df = pd.DataFrame(bsLine)
|
||||
df = df.fillna(-1)
|
||||
buy_count = len(df.loc[df["buy"] > 0])
|
||||
sell_count = len(df.loc[df["sell"] > 0])
|
||||
|
||||
fig.update_layout(height=1700, title=stock_code + "_" + given_day + "_" + str(buy_count)+","+str(sell_count))
|
||||
#fig.update_layout(title=stock_code + "_" + given_day + "_" + str(buy_count) + "," + str(sell_count))
|
||||
fig.show()
|
||||
|
||||
return
|
||||
|
||||
|
||||
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 simulate(self, stock, analyzed_day=1000):
|
||||
stock_code = stock['code']
|
||||
for ymd in stock['ymd']:
|
||||
LAST_DATA = self.stock2Vector.getLastData(stock_code, ymd)
|
||||
# 1분봉
|
||||
result = self.stock2Vector.getRealTime(stock_code, ymd, LAST_DATA)
|
||||
# 5분봉
|
||||
#result = self.makeTickData(result, mins=5)
|
||||
# 30분봉
|
||||
#result = self.makeTickData(result, mins=30)
|
||||
|
||||
data = self.buySellChecker.analyze(result)
|
||||
data.drop(data.index[:len(data) - analyzed_day], inplace=True)
|
||||
|
||||
# 이동평균, RSI, MACD, 일목균형, 볼린저밴드 상/하단을 계산한다.
|
||||
#data_5 = self.buySellChecker.analyze(result_5)
|
||||
# 분석일 데이터만 활용한다 (이전 데이터는 제거)
|
||||
#data_5.drop(data_5.index[:len(data_5) - analyzed_day], inplace=True)
|
||||
|
||||
#data_30 = self.buySellChecker.analyze(result_30)
|
||||
# 분석일 데이터만 활용한다 (이전 데이터는 제거)
|
||||
#data_30.drop(data_30.index[:len(data_30) - analyzed_day], inplace=True)
|
||||
|
||||
# 사야 할 시점과 팔아야 할 시점을 체크한다.
|
||||
#bsLine = self.buySellChecker.checkTransaction(stock_code, data, data_5, data_30, isRealTime=False)
|
||||
|
||||
# 어제 데이터는 지운다.
|
||||
#data = data.loc[pd.DatetimeIndex(data.index).day == int(given_day[6:])]
|
||||
bsLine = self.buySellChecker.checkTransaction(data, isRealTime=False)
|
||||
|
||||
# 그래프를 그린다.
|
||||
self.draw(stock_code, ymd, data, bsLine)
|
||||
return
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
PROJECT_HOME = os.getcwd()
|
||||
RESOURCE_PATH = os.path.join(PROJECT_HOME, "resources")
|
||||
|
||||
#day_list = ['20231016', '20231017', '20231018', '20231019', '20231020', '20231023', '20231024', '20231025', '20231026', '20231027', '20231030', '20231031', '20231101', '20231102']
|
||||
day_list = ['20231113']
|
||||
stocks = [
|
||||
{'code': '252670', 'name': 'KODEX 200선물인버스2X', 'ymd': day_list},
|
||||
{'code': '122630', 'name': 'KODEX 레버리지', 'ymd': day_list},
|
||||
{'code': '233740', 'name': 'KODEX 코스닥150레버리지', 'ymd': day_list},
|
||||
{'code': '251340', 'name': 'KODEX 코스닥150선물인버스', 'ymd': day_list}
|
||||
]
|
||||
|
||||
for stock in stocks:
|
||||
simulation = Simulation(RESOURCE_PATH)
|
||||
simulation.simulate(stock)
|
||||
print ("done...")
|
||||
@@ -1,15 +1,10 @@
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import shutil
|
||||
import time
|
||||
import sqlite3
|
||||
from datetime import datetime
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from stock.crawler.FnGuideCrawler import FnGuideCrawler
|
||||
from stock.crawler.MetaCrawler import MetaCrawler
|
||||
from stock.crawler.StockCrawler import StockCrawler
|
||||
from stock.analysis.AnalyzerSqlite import AnalyzerSqlite
|
||||
|
||||
|
||||
class StockCrawlerDaily:
|
||||
@@ -113,27 +108,6 @@ class StockCrawlerDaily:
|
||||
print("\n[US 종목 수집]")
|
||||
stockCrawler.crawl_special_stocks(stockFileName)
|
||||
|
||||
analyzerSqlite = AnalyzerSqlite(RESOURCE_PATH)
|
||||
|
||||
print("\n[종목 결정]")
|
||||
# HTML 출력
|
||||
outPath = os.path.join(self.PROJECT_HOME, "resources", "analysis")
|
||||
if not os.path.isdir(outPath):
|
||||
os.mkdir(outPath)
|
||||
day = datetime.today().strftime("%Y%m%d")
|
||||
before_7_day = datetime.today() + relativedelta(days=-7)
|
||||
dayList = os.listdir(outPath)
|
||||
for dayDir in dayList:
|
||||
if dayDir[0] != '.' and dayDir < before_7_day.strftime("%Y%m%d"):
|
||||
if os.path.exists(os.path.join(outPath, dayDir)) and os.path.isdir(os.path.join(outPath, dayDir)):
|
||||
shutil.rmtree(os.path.join(outPath, dayDir))
|
||||
outPath = os.path.join(outPath, day)
|
||||
if os.path.isdir(outPath):
|
||||
shutil.rmtree(outPath)
|
||||
os.mkdir(outPath)
|
||||
|
||||
analyzerSqlite.findCandidates(outPath)
|
||||
|
||||
return
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
@app.get("/")
|
||||
async def root():
|
||||
return {"message": "Hello World"}
|
||||
@@ -1,65 +0,0 @@
|
||||
import os
|
||||
import keras
|
||||
import numpy as np
|
||||
import tensorflow as tf
|
||||
from stock.util.Stock2Vector import Stock2Vector
|
||||
from classification_models.keras import Classifiers
|
||||
|
||||
class StockTrainer:
|
||||
|
||||
RESOURCE_PATH = None
|
||||
stock2Vector = None
|
||||
|
||||
def __init__(self, RESOURCE_PATH):
|
||||
self.RESOURCE_PATH = RESOURCE_PATH
|
||||
self.stock2Vector = Stock2Vector(RESOURCE_PATH)
|
||||
return
|
||||
|
||||
|
||||
def train(self, stock_code):
|
||||
#X, Y = self.stock2Vector.getDataset3D(stock_code)
|
||||
X, Y = self.stock2Vector.getDataset2D(stock_code)
|
||||
|
||||
# build model
|
||||
n_classes = 3
|
||||
Inceptionresnetv2, preprocess_input = Classifiers.get('inceptionresnetv2')
|
||||
X = preprocess_input(X)
|
||||
|
||||
# train
|
||||
checkpoint_filename = os.path.join(self.RESOURCE_PATH, "model", "stock.ckpt")
|
||||
base_model = Inceptionresnetv2(input_shape=(299, 299, 3), include_top=False)
|
||||
x = tf.keras.layers.GlobalAveragePooling2D()(base_model.output)
|
||||
output = tf.keras.layers.Dense(n_classes, activation='softmax')(x)
|
||||
model = keras.models.Model(inputs=[base_model.input], outputs=[output])
|
||||
|
||||
model.compile(optimizer='SGD', loss='categorical_crossentropy', metrics=['accuracy'])
|
||||
chekpoint = tf.keras.callbacks.ModelCheckpoint(filepath=checkpoint_filename, save_weights_only=True, verbose=1)
|
||||
earlystop = tf.keras.callbacks.EarlyStopping(monitor='loss', patience=5, mode="auto")
|
||||
|
||||
if os.path.isfile(checkpoint_filename):
|
||||
model.load_weights(checkpoint_filename)
|
||||
|
||||
model.fit(x=X,
|
||||
y=Y,
|
||||
batch_size=10000,
|
||||
epochs=10000,
|
||||
callbacks=[chekpoint, earlystop])
|
||||
|
||||
return
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
PROJECT_HOME = os.getcwd()
|
||||
RESOURCE_PATH = os.path.join(PROJECT_HOME, "resources")
|
||||
|
||||
stock_codes = {
|
||||
# 252670
|
||||
# 122630
|
||||
"252670": ['20220729'],
|
||||
}
|
||||
|
||||
for stock_code in stock_codes:
|
||||
stockTrainer = StockTrainer(RESOURCE_PATH)
|
||||
stockTrainer.train(stock_code)
|
||||
|
||||
print ("done...")
|
||||
240
VitTrainer.py
240
VitTrainer.py
@@ -1,240 +0,0 @@
|
||||
# tensor - numpy - PILImage 변환 (https://qlsenddl-lab.tistory.com/37)
|
||||
|
||||
import os
|
||||
os.environ['KMP_DUPLICATE_LIB_OK']='True'
|
||||
import random
|
||||
import numpy as np
|
||||
import torch
|
||||
from datasets import Dataset, load_metric, ClassLabel
|
||||
from datasets import load_metric
|
||||
from transformers import ViTConfig, TrainingArguments, Trainer, ViTForImageClassification
|
||||
from torch.utils.data import DataLoader
|
||||
import torchvision.transforms as transforms
|
||||
from transformers import ViTFeatureExtractor
|
||||
from torchvision.transforms import (CenterCrop, Compose, Normalize, RandomHorizontalFlip, RandomResizedCrop, Resize, ToTensor)
|
||||
|
||||
from stock.util.Stock2Vector import Stock2Vector
|
||||
|
||||
class VitTrainer:
|
||||
|
||||
RESOURCE_PATH = None
|
||||
stock2Vector = None
|
||||
|
||||
num_labels = None
|
||||
id2label = None
|
||||
label2id = None
|
||||
|
||||
args = None
|
||||
|
||||
_train_transforms = None
|
||||
_val_transforms = None
|
||||
|
||||
def __init__(self, RESOURCE_PATH):
|
||||
self.set_seed(42)
|
||||
|
||||
self.RESOURCE_PATH = RESOURCE_PATH
|
||||
self.stock2Vector = Stock2Vector(RESOURCE_PATH)
|
||||
|
||||
self.num_labels = 3
|
||||
self.id2label = {0: 'none', 1: 'sell', 2: 'buy'}
|
||||
self.label2id = {'none': 0, 'sell': 1, 'buy': 2}
|
||||
|
||||
self.args = TrainingArguments(
|
||||
os.path.join(self.RESOURCE_PATH, 'model', f"stock_vit_predictor"),
|
||||
save_strategy="epoch",
|
||||
evaluation_strategy="epoch",
|
||||
learning_rate=2e-5,
|
||||
per_device_train_batch_size=128,
|
||||
per_device_eval_batch_size=128,
|
||||
weight_decay=0.01,
|
||||
load_best_model_at_end=True,
|
||||
metric_for_best_model="accuracy",
|
||||
logging_dir=os.path.join(self.RESOURCE_PATH, 'model', 'logs'),
|
||||
remove_unused_columns=False,
|
||||
num_train_epochs=24,
|
||||
)
|
||||
|
||||
return
|
||||
|
||||
def set_seed(self, seed=42, n_gpu=0):
|
||||
random.seed(seed)
|
||||
np.random.seed(seed)
|
||||
torch.manual_seed(seed)
|
||||
if n_gpu > 0:
|
||||
torch.cuda.manual_seed_all(seed)
|
||||
|
||||
def train_transforms(self, examples):
|
||||
examples['pixel_values'] = [self._train_transforms(image.convert("RGB")) for image in examples['img']]
|
||||
return examples
|
||||
|
||||
def val_transforms(self, examples):
|
||||
examples['pixel_values'] = [self._val_transforms(image.convert("RGB")) for image in examples['img']]
|
||||
return examples
|
||||
|
||||
def collate_fn(self, examples):
|
||||
pixel_values = torch.stack([example["pixel_values"] for example in examples])
|
||||
labels = torch.tensor([example["label"] for example in examples])
|
||||
return {"pixel_values": pixel_values, "labels": labels}
|
||||
|
||||
def compute_metrics(self, eval_pred):
|
||||
predictions, labels = eval_pred
|
||||
predictions = np.argmax(predictions, axis=1)
|
||||
metric = load_metric("accuracy")
|
||||
return metric.compute(predictions=predictions, references=labels)
|
||||
|
||||
def getFeature(self, model_path=None):
|
||||
if model_path == None:
|
||||
self.feature_extractor = ViTFeatureExtractor.from_pretrained("google/vit-base-patch16-224-in21k")
|
||||
#self.feature_extractor = ViTFeatureExtractor()
|
||||
else:
|
||||
#self.feature_extractor = ViTFeatureExtractor.from_pretrained("google/vit-base-patch16-224-in21k")
|
||||
self.feature_extractor = ViTFeatureExtractor.from_pretrained(model_path)
|
||||
|
||||
normalize = Normalize(mean=self.feature_extractor.image_mean, std=self.feature_extractor.image_std)
|
||||
self._train_transforms = Compose(
|
||||
[
|
||||
RandomResizedCrop(self.feature_extractor.size),
|
||||
RandomHorizontalFlip(),
|
||||
ToTensor(),
|
||||
normalize,
|
||||
]
|
||||
)
|
||||
|
||||
self._val_transforms = Compose(
|
||||
[
|
||||
Resize(self.feature_extractor.size),
|
||||
CenterCrop(self.feature_extractor.size),
|
||||
ToTensor(),
|
||||
normalize,
|
||||
]
|
||||
)
|
||||
return
|
||||
|
||||
def train(self, train_ds, val_ds, model_path):
|
||||
self.getFeature()
|
||||
|
||||
# Set the transforms
|
||||
train_ds.set_transform(self.train_transforms)
|
||||
val_ds.set_transform(self.val_transforms)
|
||||
|
||||
train_dataloader = DataLoader(train_ds, collate_fn=self.collate_fn, batch_size=32)
|
||||
|
||||
batch = next(iter(train_dataloader))
|
||||
for k,v in batch.items():
|
||||
if isinstance(v, torch.Tensor):
|
||||
print(k, v.shape)
|
||||
|
||||
"""
|
||||
model = ViTForImageClassification.from_pretrained('google/vit-base-patch16-224-in21k',
|
||||
num_labels=self.num_labels,
|
||||
id2label=self.id2label,
|
||||
label2id=self.label2id)
|
||||
"""
|
||||
configuration = ViTConfig(num_labels=self.num_labels,
|
||||
id2label=self.id2label,
|
||||
label2id=self.label2id)
|
||||
model = ViTForImageClassification(configuration)
|
||||
|
||||
trainer = Trainer(
|
||||
model,
|
||||
self.args,
|
||||
train_dataset=train_ds,
|
||||
eval_dataset=val_ds,
|
||||
data_collator=self.collate_fn,
|
||||
compute_metrics=self.compute_metrics,
|
||||
tokenizer=self.feature_extractor
|
||||
)
|
||||
|
||||
trainer.train()
|
||||
|
||||
# save trained model
|
||||
model_to_save = (model.module if hasattr(model, "module") else model) # Take care of distributed/parallel training
|
||||
model_to_save.save_pretrained(model_path)
|
||||
self.feature_extractor.save_pretrained(model_path)
|
||||
torch.save(self.args, os.path.join(RESOURCE_PATH, "model", "training_args.bin"))
|
||||
|
||||
return
|
||||
|
||||
def finetunning(self, train_ds, val_ds, model_path):
|
||||
self.getFeature(model_path)
|
||||
|
||||
# Set the transforms
|
||||
train_ds.set_transform(self.train_transforms)
|
||||
val_ds.set_transform(self.val_transforms)
|
||||
|
||||
train_dataloader = DataLoader(train_ds, collate_fn=self.collate_fn, batch_size=32)
|
||||
|
||||
batch = next(iter(train_dataloader))
|
||||
for k,v in batch.items():
|
||||
if isinstance(v, torch.Tensor):
|
||||
print(k, v.shape)
|
||||
|
||||
model = ViTForImageClassification.from_pretrained(model_path,
|
||||
num_labels=self.num_labels,
|
||||
id2label=self.id2label,
|
||||
label2id=self.label2id)
|
||||
trainer = Trainer(
|
||||
model,
|
||||
self.args,
|
||||
train_dataset=train_ds,
|
||||
eval_dataset=val_ds,
|
||||
data_collator=self.collate_fn,
|
||||
compute_metrics=self.compute_metrics,
|
||||
tokenizer=self.feature_extractor
|
||||
)
|
||||
|
||||
trainer.train()
|
||||
|
||||
# save trained model
|
||||
model_to_save = (model.module if hasattr(model, "module") else model) # Take care of distributed/parallel training
|
||||
model_to_save.save_pretrained(model_path)
|
||||
self.feature_extractor.save_pretrained(model_path)
|
||||
torch.save(self.args, os.path.join(RESOURCE_PATH, "model", "training_args.bin"))
|
||||
|
||||
return
|
||||
|
||||
def getData(self, stock_code, sDate, eDate):
|
||||
# Instance Normalization를 NumPy 및 PyTorch로 구현하는 방법! (https://ndb796.tistory.com/653)
|
||||
data = self.stock2Vector.getTrainData(stock_code, sDate, eDate)
|
||||
#X, Y = self.stock2Vector.getDataset2D(data)
|
||||
X, Y = self.stock2Vector.getVectorData(data)
|
||||
print("Data count: ", len(X))
|
||||
|
||||
trans = transforms.ToPILImage()
|
||||
#X = [trans(torch.tensor([x])) for x in X]
|
||||
X = [trans(torch.tensor(x)) for x in X]
|
||||
|
||||
split_point1 = int(len(X) * 0.9)
|
||||
train_X = X[:split_point1]
|
||||
train_Y = Y[:split_point1]
|
||||
valid_X = X[split_point1:]
|
||||
valid_Y = Y[split_point1:]
|
||||
|
||||
# load cifar10 (only small portion for demonstration purposes)
|
||||
train_data = {'img': train_X, 'label': train_Y}
|
||||
val_dsta = {'img': valid_X, 'label': valid_Y}
|
||||
|
||||
train_ds = Dataset.from_dict(train_data)
|
||||
val_ds = Dataset.from_dict(val_dsta)
|
||||
|
||||
features = train_ds.features.copy()
|
||||
features["label"] = ClassLabel(num_classes=self.num_labels, names=["none", "sell", "buy"])
|
||||
def adjust_labels(batch):
|
||||
batch["label"] = [lbl for lbl in batch["label"]]
|
||||
return batch
|
||||
train_ds = train_ds.map(adjust_labels, batched=True, features=features)
|
||||
val_ds = train_ds.map(adjust_labels, batched=True, features=features)
|
||||
|
||||
return train_ds, val_ds
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
PROJECT_HOME = os.getcwd()
|
||||
RESOURCE_PATH = os.path.join(PROJECT_HOME, "resources")
|
||||
model_path = os.path.join(RESOURCE_PATH, "model")
|
||||
|
||||
stock_code = "252670"
|
||||
vitTrainer = VitTrainer(RESOURCE_PATH)
|
||||
|
||||
train_ds, val_ds = vitTrainer.getData(stock_code, sDate="20220501", eDate="20220819")
|
||||
vitTrainer.train(train_ds, val_ds, model_path)
|
||||
@@ -1,594 +0,0 @@
|
||||
import os
|
||||
import time
|
||||
import shutil
|
||||
import matplotlib.pyplot as plt
|
||||
import datetime
|
||||
import sqlite3
|
||||
import math
|
||||
from math import nan
|
||||
from datetime import datetime, timedelta
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from matplotlib import rc
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
from stock.analysis.JSDPattern_simulation import JSDPattern_simulation
|
||||
from hts.BuySell_Daily import BuySell_Daily
|
||||
|
||||
rc('font', family='AppleGothic')
|
||||
plt.rcParams['axes.unicode_minus'] = False
|
||||
|
||||
import plotly.graph_objs as go
|
||||
from plotly import subplots
|
||||
import plotly.io as po
|
||||
|
||||
from stock.analysis.Common import Common
|
||||
from stock.util.TelegramBot import TelegramBot
|
||||
|
||||
class AnalyzerSqlite:
|
||||
jSDPattern = None
|
||||
buySell_Daily = None
|
||||
topCompany = None
|
||||
fnguide = None
|
||||
|
||||
bot = None
|
||||
|
||||
common = None
|
||||
stockFileName = None
|
||||
analyzedFileName = None
|
||||
|
||||
moving_avg = None
|
||||
|
||||
def __init__(self, RESOURCE_PATH):
|
||||
self.common = Common()
|
||||
|
||||
self.stockFileName = os.path.join(RESOURCE_PATH, 'stock.db')
|
||||
self.jSDPattern = JSDPattern_simulation(self.stockFileName)
|
||||
self.buySell_Daily = BuySell_Daily()
|
||||
self.stockFileName = self.stockFileName
|
||||
self.topCompany = self.getTopCompany(self.stockFileName, 2000)
|
||||
self.fnguide = self.readFnguide(self.stockFileName)
|
||||
|
||||
self.bot = TelegramBot()
|
||||
|
||||
return
|
||||
|
||||
def getTopCompany(self, fnguideFileName, top):
|
||||
conn = sqlite3.connect(fnguideFileName)
|
||||
cursor = conn.cursor()
|
||||
|
||||
sql = "select DISTINCT CODE, NAME from fnguide order by total_ownership_interest desc limit " + str(top)
|
||||
cursor.execute(sql)
|
||||
result = cursor.fetchall()
|
||||
|
||||
top_company = {}
|
||||
for idx, item in enumerate(result):
|
||||
top_company[item[0]] = (idx+1, item[1])
|
||||
|
||||
cursor.close()
|
||||
conn.close()
|
||||
return top_company
|
||||
|
||||
def readFnguide(self, fnguideFileName):
|
||||
conn = sqlite3.connect(fnguideFileName)
|
||||
cursor = conn.cursor()
|
||||
|
||||
today = datetime.today()
|
||||
year1 = str(today.year - 1) + ".12.01"
|
||||
year2 = str(today.year - 2) + ".12.01"
|
||||
year3 = str(today.year - 3) + ".12.01"
|
||||
|
||||
sql = "SELECT CODE, NAME, ymd, business_profits, business_profits_ratio, debt_ratio, ROA, ROE, EPS, BPS, DPS, PER, PBR FROM fnguide "
|
||||
sql += " WHERE (ymd=? or ymd=? or ymd=?) and type=''"
|
||||
sql += " order by code, ymd desc"
|
||||
cursor.execute(sql, (year1,year2,year3))
|
||||
result = cursor.fetchall()
|
||||
|
||||
fnguide = {}
|
||||
for item in result:
|
||||
if item[0] not in fnguide:
|
||||
fnguide[item[0]] = []
|
||||
|
||||
fnguide[item[0]].append(
|
||||
{'NAME': item[1],
|
||||
'ymd': item[2],
|
||||
'business_profits': item[3],
|
||||
'business_profits_ratio': item[4],
|
||||
'debt_ratio': item[5],
|
||||
'ROA': item[6],
|
||||
'ROE': item[7],
|
||||
'EPS': item[8],
|
||||
'BPS': item[9],
|
||||
'DPS': item[10],
|
||||
'PER': item[11],
|
||||
'PBR': item[12]})
|
||||
|
||||
cursor.close()
|
||||
conn.close()
|
||||
return fnguide
|
||||
|
||||
|
||||
def cz(self, value):
|
||||
if value is None or math.isnan(value):
|
||||
return 0
|
||||
|
||||
return value
|
||||
|
||||
|
||||
def clear_BSLINE(self, BUY_LIST, sell_type=None):
|
||||
if sell_type is None or sell_type == '':
|
||||
BUY_LIST['avg_buy_price'] = 0
|
||||
BUY_LIST['buy_count'] = 0
|
||||
BUY_LIST['buy_list'].clear()
|
||||
else:
|
||||
BUY_LIST['avg_buy_price'] = 0
|
||||
BUY_LIST['buy_count'] = 0
|
||||
|
||||
tmp_sell_type = sell_type.split(',')
|
||||
for i, buy_list in reversed(list(enumerate(BUY_LIST['buy_list']))):
|
||||
for t_sell_type in tmp_sell_type:
|
||||
if buy_list['buy_type'].strip() == t_sell_type.strip():
|
||||
del BUY_LIST['buy_list'][i]
|
||||
break
|
||||
return
|
||||
|
||||
def draw(self, stock_code, data, bsLine=None):
|
||||
|
||||
# 어제 데이터는 지운다.
|
||||
#data = data.loc[pd.DatetimeIndex(data.index).day == int(given_day[6:])]
|
||||
buy_price_line, buy_count_line, buy_type, buy_count_line, sell_price_line, sell_count_line, sell_type = [], [], [], [], [], [], []
|
||||
buy_sell_size, buy_colors, sell_colors, buy_colors = [], [], [], []
|
||||
|
||||
if bsLine is not None:
|
||||
buy_price_line = bsLine['buy_price']
|
||||
buy_count_line = bsLine['buy_count']
|
||||
sell_price_line = bsLine['sell_price']
|
||||
sell_count_line = bsLine['sell_count']
|
||||
buy_type = bsLine['buy_type']
|
||||
sell_type = bsLine['sell_type']
|
||||
|
||||
for i in range(len(data)):
|
||||
if buy_price_line[i] < 1:
|
||||
buy_colors.append("#ffffff")
|
||||
buy_price_line[i] = nan
|
||||
buy_sell_size.append(0)
|
||||
else:
|
||||
buy_colors.append("#0C752E")
|
||||
buy_sell_size.append(14)
|
||||
for i in range(len(data)):
|
||||
if sell_price_line[i] < 1:
|
||||
sell_colors.append("#ffffff")
|
||||
sell_price_line[i] = nan
|
||||
else:
|
||||
sell_colors.append("#00ced1")
|
||||
|
||||
volume_colors = []
|
||||
for i in range(len(data)):
|
||||
if data['open'][i] > data['close'][i]:
|
||||
volume_colors.append("#FF0000")
|
||||
elif data['open'][i] < data['close'][i]:
|
||||
volume_colors.append("#FF0000")
|
||||
else:
|
||||
volume_colors.append("#000000")
|
||||
|
||||
# 그래프를 설정한다.
|
||||
if bsLine is not None:
|
||||
buy_text_list, sell_text_list = [], []
|
||||
for i in range(len(data['ymd'])):
|
||||
buy_text_list.append(
|
||||
"{}, {}, {} ({:,.2f})<br><br>"
|
||||
"avg5: {:.2f}, avg10: {:.2f}, avg20: {:.2f}, avg60: {:.2f}, avg90: {:.2f}, avg120: {:.2f}, avg240: {:.2f}<br>"
|
||||
"avg360: {:.2f}, avg480: {:.2f}, avg720: {:.2f}, avg1440: {:.2f}, avg2880: {:.2f}<br><br>"
|
||||
"loc_k: {:.2f}, loc_d: {:.2f}, loc_s: {:.2f}<br><br>"
|
||||
"laggingSpan_close_diff: {:.4f} ({:.4f})<br>"
|
||||
"laggingSpan_avg60_diff: {:.4f} ({:.4f})<br>"
|
||||
"leadingSpan1_leadingSpan2_diff: {:.4f} ({:.4f})<br>"
|
||||
.format(data['ymd'][i].strftime('%Y-%m-%d %H:%M'), buy_type[i], self.cz(buy_price_line[i]), self.cz(buy_price_line[i])*self.cz(buy_count_line[i]),
|
||||
self.cz(data["avg5"][i]), self.cz(data["avg10"][i]), self.cz(data["avg20"][i]), self.cz(data["avg60"][i]), self.cz(data["avg90"][i]), self.cz(data["avg120"][i]), self.cz(data["avg240"][i]), self.cz(data["avg360"][i]), self.cz(data["avg480"][i]), self.cz(data["avg720"][i]), self.cz(data["avg1440"][i]), self.cz(data["avg2880"][i]),
|
||||
self.cz(data['loc_240_k'][i]), self.cz(data['loc_240_d'][i]), self.cz(data['loc_240_s'][i]),
|
||||
self.cz(data['laggingSpan_close_diff'][i]), self.cz(data['laggingSpan_close_diff_rate'][i]),
|
||||
self.cz(data['laggingSpan_avg60_diff'][i]), self.cz(data['laggingSpan_avg60_diff_rate'][i]),
|
||||
self.cz(data['leadingSpan1_leadingSpan2_diff'][i]), self.cz(data['leadingSpan1_leadingSpan2_diff_rate'][i])
|
||||
))
|
||||
sell_text_list.append(
|
||||
"{}, {}, {} ({:,.2f})<br><br>"
|
||||
"avg5: {:.2f}, avg10: {:.2f}, avg20: {:.2f}, avg60: {:.2f}, avg90: {:.2f}, avg120: {:.2f}, avg240: {:.2f}<br>"
|
||||
"avg360: {:.2f}, avg480: {:.2f}, avg720: {:.2f}, avg1440: {:.2f}, avg2880: {:.2f}<br><br>"
|
||||
"loc_k: {:.2f}, loc_d: {:.2f}, loc_s: {:.2f}<br><br>"
|
||||
"laggingSpan_close_diff: {:.4f} ({:.4f})<br>"
|
||||
"laggingSpan_avg60_diff: {:.4f} ({:.4f})<br>"
|
||||
"leadingSpan1_leadingSpan2_diff: {:.4f} ({:.4f})<br>"
|
||||
.format(
|
||||
data['ymd'][i].strftime('%Y-%m-%d %H:%M'), sell_type[i], self.cz(sell_price_line[i]), self.cz(sell_price_line[i])*self.cz(sell_count_line[i]),
|
||||
self.cz(data["avg5"][i]), self.cz(data["avg10"][i]), self.cz(data["avg20"][i]), self.cz(data["avg60"][i]), self.cz(data["avg90"][i]), self.cz(data["avg120"][i]), self.cz(data["avg240"][i]), self.cz(data["avg360"][i]), self.cz(data["avg480"][i]), self.cz(data["avg720"][i]), self.cz(data["avg1440"][i]), self.cz(data["avg2880"][i]),
|
||||
self.cz(data['loc_240_k'][i]), self.cz(data['loc_240_d'][i]), self.cz(data['loc_240_s'][i]),
|
||||
self.cz(data['laggingSpan_close_diff'][i]), self.cz(data['laggingSpan_close_diff_rate'][i]),
|
||||
self.cz(data['laggingSpan_avg60_diff'][i]), self.cz(data['laggingSpan_avg60_diff_rate'][i]),
|
||||
self.cz(data['leadingSpan1_leadingSpan2_diff'][i]), self.cz(data['leadingSpan1_leadingSpan2_diff_rate'][i])
|
||||
))
|
||||
buy_check = go.Scatter(x=data['ymd'], y=buy_price_line, mode='markers', name="buy_price", marker=dict(size=buy_sell_size, color=buy_colors, line_width=0), text=buy_text_list, hoverinfo="text")
|
||||
sell_check = go.Scatter(x=data['ymd'], y=sell_price_line, mode='markers', name="sell_price", marker=dict(size=14, color=sell_colors, line_width=0), text=sell_text_list, hoverinfo="text")
|
||||
|
||||
volume_line = go.Bar(x=data['ymd'], y=data["volume"], marker_color=volume_colors, name='volume')
|
||||
|
||||
avg5 = go.Scatter(x=data['ymd'], y=data["avg5"], name="avg5", line_color='#079118')
|
||||
avg10 = go.Scatter(x=data['ymd'], y=data["avg10"], name="avg10", line_color='grey')
|
||||
avg20 = go.Scatter(x=data['ymd'], y=data["avg20"], name="avg20", line_color='#d755e8')
|
||||
avg60 = go.Scatter(x=data['ymd'], y=data["avg60"], name="avg60", line_color='#099B92')
|
||||
avg90 = go.Scatter(x=data['ymd'], y=data["avg90"], name="avg90", line_color='#2a9c0c')
|
||||
avg120 = go.Scatter(x=data['ymd'], y=data["avg120"], name="avg120", line_color='#079118')
|
||||
avg240 = go.Scatter(x=data['ymd'], y=data["avg240"], name="avg240", line_color='#e68456')
|
||||
avg360 = go.Scatter(x=data['ymd'], y=data["avg360"], name="avg360", line_color='#e6b55c')
|
||||
avg480 = go.Scatter(x=data['ymd'], y=data["avg480"], name="avg480", line_color='#2a9c0c')
|
||||
avg720 = go.Scatter(x=data['ymd'], y=data["avg720"], name="avg720", line_color='#e75d53')
|
||||
avg1440 = go.Scatter(x=data['ymd'], y=data["avg1440"], name="avg1440", line_color='#2a9c0c')
|
||||
avg2880 = go.Scatter(x=data['ymd'], y=data["avg2880"], name="avg2880", line_color='#46406c')
|
||||
|
||||
laggingSpan_0_8_limit = [0.8 for i in data['ymd']]
|
||||
laggingSpan_0_2_limit = [0.2 for i in data['ymd']]
|
||||
laggingSpan_0_limit = [0 for i in data['ymd']]
|
||||
laggingSpan__0_2_limit = [-0.2 for i in data['ymd']]
|
||||
laggingSpan__0_8_limit = [-0.8 for i in data['ymd']]
|
||||
laggingSpan_0_8_limit_line = go.Scatter(x=data['ymd'], y=laggingSpan_0_8_limit, line=dict(color='grey', width=1), name='laggingSpan_0_8_limit')
|
||||
laggingSpan_0_2_limit_line = go.Scatter(x=data['ymd'], y=laggingSpan_0_2_limit, line=dict(color='grey', width=1), name='laggingSpan_0_2_limit')
|
||||
laggingSpan_0_limit_line = go.Scatter(x=data['ymd'], y=laggingSpan_0_limit, line=dict(color='grey', width=1), name='laggingSpan_0_limit')
|
||||
laggingSpan__0_2_limit_line = go.Scatter(x=data['ymd'], y=laggingSpan__0_2_limit, line=dict(color='grey', width=1), name='laggingSpan__0_2_limit')
|
||||
laggingSpan__0_8_limit_line = go.Scatter(x=data['ymd'], y=laggingSpan__0_8_limit, line=dict(color='grey', width=1), name='laggingSpan__0_8_limit')
|
||||
|
||||
laggingSpan_close_diff = go.Scatter(x=data['ymd'], y=data["laggingSpan_close_diff"], name="laggingSpan_close_diff", line_color='#079118')
|
||||
laggingSpan_avg60_diff = go.Scatter(x=data['ymd'], y=data["laggingSpan_avg60_diff"], name="laggingSpan_avg60_diff", line_color='#d755e8')
|
||||
leadingSpan1_leadingSpan2_diff = go.Scatter(x=data['ymd'], y=data["leadingSpan1_leadingSpan2_diff"], name="leadingSpan1_leadingSpan2_diff", line_color='#d755e8')
|
||||
|
||||
laggingSpan_close_diff_rate = go.Scatter(x=data['ymd'], y=data["laggingSpan_close_diff_rate"], name="laggingSpan_close_diff_rate", line_color='#d755e8')
|
||||
laggingSpan_avg60_diff_rate = go.Scatter(x=data['ymd'], y=data["laggingSpan_avg60_diff_rate"], name="laggingSpan_avg60_diff_rate", line_color='#d755e8')
|
||||
leadingSpan1_leadingSpan2_diff_rate = go.Scatter(x=data['ymd'], y=data["leadingSpan1_leadingSpan2_diff_rate"], name="leadingSpan1_leadingSpan2_diff_rate", line_color='#d755e8')
|
||||
|
||||
changeLine = go.Scatter(x=data['ymd'], y=data["changeLine"], name="changeLine", line_color='#0196ff')
|
||||
baseLine = go.Scatter(x=data['ymd'], y=data["baseLine"], name="baseLine", line_color='#991515')
|
||||
laggingSpan = go.Scatter(x=data['ymd'], y=data["laggingSpan"], name="laggingSpan", line_color='#12A524')
|
||||
leadingSpan1 = go.Scatter(x=data['ymd'], y=data["leadingSpan1"], name="leadingSpan1", line_color='#008001')
|
||||
leadingSpan2 = go.Scatter(x=data['ymd'], y=data["leadingSpan2"], name="leadingSpan2", line_color='#830fd4')
|
||||
|
||||
upper_10_Line = go.Scatter(x=data['ymd'], y=data["upper_10"], name="upper_10", line_color='#0196ff')
|
||||
lower_10_Line = go.Scatter(x=data['ymd'], y=data["lower_10"], name="lower_10", line_color='#991515')
|
||||
middle_10_line = go.Scatter(x=data['ymd'], y=data["middle_10"], name="middle_10", line_color='#12A524')
|
||||
upper_20_Line = go.Scatter(x=data['ymd'], y=data["upper_20"], name="upper_20", line_color='#0196ff')
|
||||
lower_20_Line = go.Scatter(x=data['ymd'], y=data["lower_20"], name="lower_20", line_color='#991515')
|
||||
middle_20_line = go.Scatter(x=data['ymd'], y=data["middle_20"], name="middle_20", line_color='#12A524')
|
||||
|
||||
loc_240_k = go.Scatter(x=data['ymd'], y=data["loc_240_k"], name="loc_240_k", line_color='#0196ff')
|
||||
loc_240_d = go.Scatter(x=data['ymd'], y=data["loc_240_d"], name="loc_240_d", line_color='#991515')
|
||||
loc_240_s = go.Scatter(x=data['ymd'], y=data["loc_240_s"], name="loc_240_s", line_color='#12A524')
|
||||
|
||||
new_high_9 = go.Scatter(x=data['ymd'], y=data["new_high_9"], name="new_high_9", line_color='#0196ff')
|
||||
new_high_26 = go.Scatter(x=data['ymd'], y=data["new_high_26"], name="new_high_26", line_color='#991515')
|
||||
new_low_9 = go.Scatter(x=data['ymd'], y=data["new_low_9"], name="new_low_9", line_color='#0196ff')
|
||||
new_low_26 = go.Scatter(x=data['ymd'], y=data["new_low_26"], name="new_low_26", line_color='#991515')
|
||||
|
||||
|
||||
slowk_up_limit = [80 for i in data['ymd']]
|
||||
slowk_middle_limit = [50 for i in data['ymd']]
|
||||
slowk_down_limit = [20 for i in data['ymd']]
|
||||
slowk_up_limit = go.Scatter(x=data['ymd'], y=slowk_up_limit, line=dict(color='grey', width=1), name='slowk_up_limit')
|
||||
slowk_middle_limit = go.Scatter(x=data['ymd'], y=slowk_middle_limit, line=dict(color='grey', width=1), name='slowk_middle_limit')
|
||||
slowk_down_limit = go.Scatter(x=data['ymd'], y=slowk_down_limit, line=dict(color='grey', width=1), name='slowk_down_limit')
|
||||
|
||||
slowk_12 = go.Scatter(x=data['ymd'], y=data["slowk_12"], line=dict(color='#079118', width=2), name='slowk_12')
|
||||
slowd_12 = go.Scatter(x=data['ymd'], y=data["slowd_12"], line=dict(dash='dashdot', color='#079118', width=2), name='slowd_12')
|
||||
slowk_26 = go.Scatter(x=data['ymd'], y=data["slowk_26"], line=dict(color='grey', width=2), name='slowk_26')
|
||||
slowd_26 = go.Scatter(x=data['ymd'], y=data["slowd_26"], line=dict(dash='dashdot', color='grey', width=2), name='slowd_26')
|
||||
slowk_52 = go.Scatter(x=data['ymd'], y=data["slowk_52"], line=dict(color='#d755e8', width=2), name='slowk_52')
|
||||
slowd_52 = go.Scatter(x=data['ymd'], y=data["slowd_52"], line=dict(dash='dashdot', color='#d755e8', width=2), name='slowd_52')
|
||||
|
||||
|
||||
text_list = []
|
||||
for i in range(len(data['ymd'])):
|
||||
text_list.append(
|
||||
"{}<br><br>"
|
||||
"avg5: {:.2f}, avg10: {:.2f}, avg20: {:.2f}, avg60: {:.2f}, avg90: {:.2f}, avg120: {:.2f}, avg240: {:.2f}<br>"
|
||||
"avg360: {:.2f}, avg480: {:.2f}, avg720: {:.2f}, avg1440: {:.2f}, avg2880: {:.2f}<br><br>"
|
||||
"loc_k: {:.2f}, loc_d: {:.2f}, loc_s: {:.2f}<br><br>"
|
||||
"laggingSpan_close_diff: {:.4f} ({:.4f})<br>"
|
||||
"laggingSpan_avg60_diff: {:.4f} ({:.4f})<br>"
|
||||
"leadingSpan1_leadingSpan2_diff: {:.4f} ({:.4f})<br>"
|
||||
.format(
|
||||
data['ymd'][i].strftime('%Y-%m-%d %H:%M'),
|
||||
self.cz(data["avg5"][i]), self.cz(data["avg10"][i]), self.cz(data["avg20"][i]), self.cz(data["avg60"][i]), self.cz(data["avg90"][i]), self.cz(data["avg120"][i]), self.cz(data["avg240"][i]), self.cz(data["avg360"][i]), self.cz(data["avg480"][i]), self.cz(data["avg720"][i]), self.cz(data["avg1440"][i]), self.cz(data["avg2880"][i]),
|
||||
self.cz(data['loc_240_k'][i]), self.cz(data['loc_240_d'][i]), self.cz(data['loc_240_s'][i]),
|
||||
self.cz(data['laggingSpan_close_diff'][i]), self.cz(data['laggingSpan_close_diff_rate'][i]),
|
||||
self.cz(data['laggingSpan_avg60_diff'][i]), self.cz(data['laggingSpan_avg60_diff_rate'][i]),
|
||||
self.cz(data['leadingSpan1_leadingSpan2_diff'][i]), self.cz(data['leadingSpan1_leadingSpan2_diff_rate'][i])
|
||||
))
|
||||
|
||||
candle_stick = go.Candlestick(x=data['ymd'],
|
||||
open=data['open'], high=data['high'], low=data['low'], close=data['close'],
|
||||
increasing_line_color='red', decreasing_line_color='blue',
|
||||
name='candle', text=text_list, hoverinfo="text"
|
||||
)
|
||||
|
||||
if bsLine is not None:
|
||||
candle_data = [avg5, avg10, avg20, avg60, avg90, avg120, avg240, avg360, avg480, avg720, avg1440, avg2880, buy_check, sell_check, candle_stick, changeLine, baseLine, laggingSpan, leadingSpan1, leadingSpan2, upper_10_Line, lower_10_Line, middle_10_line, upper_20_Line, lower_20_Line, middle_20_line]
|
||||
else:
|
||||
candle_data = [avg5, avg10, avg20, avg60, avg90, avg120, avg240, avg360, avg480, avg720, avg1440, avg2880, candle_stick,changeLine, baseLine, laggingSpan, leadingSpan1, leadingSpan2]
|
||||
|
||||
volume_data = [volume_line]
|
||||
disparity_data = [laggingSpan_close_diff, laggingSpan_avg60_diff, leadingSpan1_leadingSpan2_diff]
|
||||
loc_disparity_data = [laggingSpan_0_8_limit_line, laggingSpan_0_2_limit_line, laggingSpan_0_limit_line, laggingSpan__0_2_limit_line, laggingSpan__0_8_limit_line,
|
||||
laggingSpan_close_diff_rate, laggingSpan_avg60_diff_rate, leadingSpan1_leadingSpan2_diff_rate,
|
||||
loc_240_k, loc_240_d, loc_240_s,
|
||||
new_high_9 ,new_high_26, new_low_9 ,new_low_26]
|
||||
stochastic_data = [
|
||||
slowk_up_limit, slowk_middle_limit, slowk_down_limit,
|
||||
slowk_12, slowd_12,
|
||||
slowk_26, slowd_26,
|
||||
slowk_52, slowd_52
|
||||
]
|
||||
# 그래프를 그린다.
|
||||
"""
|
||||
fig = go.Figure(data=candle_data)
|
||||
fig.update_layout(title=stock_code)
|
||||
fig.show()
|
||||
"""
|
||||
fig = subplots.make_subplots(
|
||||
rows=5, cols=1,
|
||||
subplot_titles=("이격도", "이격도 위치", "캔들", "slowkd", "거래량"),
|
||||
shared_xaxes=True, horizontal_spacing=0.03, vertical_spacing=0.01,
|
||||
row_heights=[200, 200, 700, 200, 200]
|
||||
)
|
||||
for trace in disparity_data:
|
||||
fig.append_trace(trace, 1, 1)
|
||||
for trace in loc_disparity_data:
|
||||
fig.append_trace(trace, 2, 1)
|
||||
for trace in candle_data:
|
||||
fig.append_trace(trace, 3, 1)
|
||||
for trace in stochastic_data:
|
||||
fig.append_trace(trace, 4, 1)
|
||||
for trace in volume_data:
|
||||
fig.append_trace(trace, 5, 1)
|
||||
|
||||
#fig.update_xaxes(nticks=5)
|
||||
#fig.update_layout(height=2400, title=stock_code, xaxis_rangeslider_visible=False)
|
||||
|
||||
df = pd.DataFrame(bsLine)
|
||||
df = df.fillna(-1)
|
||||
|
||||
|
||||
buy_count = 0
|
||||
if bsLine is not None:
|
||||
buy_count = len(df.loc[df["buy_price"] > 0])
|
||||
fig.update_layout(height=1400,
|
||||
title="{}, buy: {}번 ".format(stock_code, buy_count),
|
||||
xaxis_rangeslider_visible=False,
|
||||
xaxis2_rangeslider_visible=False,
|
||||
xaxis3_rangeslider_visible=False,
|
||||
xaxis4_rangeslider_visible=False
|
||||
)
|
||||
# 화면으로 출력함
|
||||
|
||||
return fig
|
||||
|
||||
|
||||
def getPositionalEnergy(self, close):
|
||||
# 260 (= 52 * 5)일 중 가장 찾은 금액과 가장 높았던 금액 중 현재가의 위치 계산
|
||||
|
||||
top = close[0]
|
||||
bottom = close[0]
|
||||
|
||||
for i in range(1, 260):
|
||||
if i >= len(close):
|
||||
break
|
||||
if top < close[i]:
|
||||
top = close[i]
|
||||
if bottom > close[i]:
|
||||
bottom = close[i]
|
||||
|
||||
if top-close[0] == 0:
|
||||
energy1 = 100.0
|
||||
else:
|
||||
energy1 = round((close[0]-bottom) / (top-close[0]), 2)
|
||||
|
||||
energy2 = round((close[0] / top), 2)
|
||||
|
||||
return energy1, energy2
|
||||
|
||||
def writeSummary(self, param):
|
||||
bull = list(param['bull'])
|
||||
bear = list(param['bear'])
|
||||
even = list(param['even'])
|
||||
ymd = [i for i in range(len(bull))]
|
||||
|
||||
bull_line = go.Scatter(x=ymd, y=bull, name="bull", line_color='#FF33A2')
|
||||
bear_line = go.Scatter(x=ymd, y=bear, name="bear", line_color='#1469F4')
|
||||
even_line = go.Scatter(x=ymd, y=even, name="even", line_color='#8B4513')
|
||||
|
||||
line_data = [bull_line, bear_line, even_line]
|
||||
|
||||
fig = subplots.make_subplots(
|
||||
rows=1, cols=1,
|
||||
subplot_titles=("주식 상황"),
|
||||
shared_xaxes=True, horizontal_spacing=0.03, vertical_spacing=0.01,
|
||||
row_heights=[800]
|
||||
)
|
||||
for trace in line_data:
|
||||
fig.append_trace(trace, 1, 1)
|
||||
|
||||
fig.update_layout(height=810, xaxis_rangeslider_visible=False)
|
||||
sum = param['bull'][0] + param['bear'][0] + param['even'][0]
|
||||
title = "[Summary] bull: %d (%.2f), bear: %d (%.2f), even: %d (%.2f)" % (param['bull'][0], param['bull'][0]/sum, param['bear'][0], param['bear'][0]/sum, param['even'][0], param['even'][0]/sum)
|
||||
fig['layout'].update(title=title)
|
||||
|
||||
#fileName = "%s/summary.html" % (self.outPath)
|
||||
#po.write_html(fig, file=fileName, auto_open=False)
|
||||
|
||||
return
|
||||
|
||||
def writeFile(self, outPath, CODE, NAME, top, stock, bsLine):
|
||||
# 3년 이내 한번이라도 영업이익이 났는지 체크를 함
|
||||
fnguide = None
|
||||
if CODE in self.fnguide:
|
||||
fnguide = self.fnguide[CODE]
|
||||
check = True
|
||||
if fnguide:
|
||||
check = False
|
||||
for item in fnguide:
|
||||
if item['business_profits'] > 0:
|
||||
check = True
|
||||
|
||||
if check:
|
||||
fig = self.draw(CODE, stock, bsLine)
|
||||
title = "%s (%s), 차트 (<a href=\"https://alphasquare.co.kr/home/stock/financial-information?code=%s\">URL1</a>, <a href=\"https://www.tradingview.com/chart/jJ8zOXz0/?symbol=KRX:%s\">URL2</a>, <a href=\"https://www.investing.com/search/?q=%s\">URL3</a>)" % (NAME, CODE, CODE, CODE, CODE)
|
||||
fig['layout'].update(title=title)
|
||||
|
||||
fileName = outPath + "/%s_%s_%s_%s.html" % (datetime.today().strftime("%Y%m%d"), top, NAME.replace(" ", ""), CODE)
|
||||
po.write_html(fig, file=fileName, auto_open=False)
|
||||
return
|
||||
|
||||
def checkVolume(self, p_volume, volume):
|
||||
if 0 < p_volume <= 10000 and p_volume * 700 < volume:
|
||||
return True
|
||||
if 10000 < p_volume <= 50000 and p_volume * 40 < volume:
|
||||
return True
|
||||
if 50000 < p_volume <= 100000 and p_volume * 25 < volume:
|
||||
return True
|
||||
if 100000 < p_volume <= 200000 and p_volume * 15 < volume:
|
||||
return True
|
||||
if 200000 < p_volume <= 700000 and p_volume * 13 < volume:
|
||||
return True
|
||||
if 700000 < p_volume <= 1000000 and p_volume * 10 < volume:
|
||||
return True
|
||||
if 5000000 < p_volume <= 5000000 and p_volume * 5 < volume:
|
||||
return True
|
||||
if 5000000 < p_volume and p_volume * 4 < volume:
|
||||
return True
|
||||
return False
|
||||
|
||||
def getStockData(self, CODE):
|
||||
data_daily, ci_daily = self.jSDPattern.getData(CODE, ymd=(datetime.now()+timedelta(days=1)).strftime('%Y%m%d'), get_days=1500)
|
||||
|
||||
return data_daily, ci_daily
|
||||
|
||||
|
||||
def makeDir(self, dir_name):
|
||||
if os.path.isdir(self.outPath + "/" + dir_name):
|
||||
os.rmdir(self.outPath + "/" + dir_name)
|
||||
os.mkdir(self.outPath + "/" + dir_name)
|
||||
return
|
||||
|
||||
def checkTransaction(self, ticker, data, ci):
|
||||
# 어제 오늘 데이터로 분석
|
||||
bsLine = {}
|
||||
|
||||
if data is not None and 'close' in data.columns:
|
||||
size = len(data["close"])
|
||||
bsLine['buy_ymd'] = [None for i in range(size)]
|
||||
bsLine['buy_price'] = [0 for i in range(size)]
|
||||
bsLine['buy_count'] = [0 for i in range(size)]
|
||||
bsLine['buy_type'] = ['' for i in range(size)]
|
||||
bsLine['buy_cut'] = [None for i in range(size)]
|
||||
bsLine['sell_price'] = [0 for i in range(size)]
|
||||
bsLine['sell_count'] = [0 for i in range(size)]
|
||||
bsLine['sell_type'] = ['' for i in range(size)]
|
||||
bsLine['sell_cut'] = [0 for i in range(size)]
|
||||
|
||||
size = ci
|
||||
start = 0
|
||||
for i in range(start, size):
|
||||
|
||||
# 매도 확인
|
||||
sell_price, sell_count, sell_type = self.buySell_Daily.getSellPrice(ticker, data, i, bsLine)
|
||||
bsLine['sell_price'][i] = sell_price
|
||||
bsLine['sell_count'][i] = sell_count
|
||||
bsLine['sell_type'][i] = sell_type
|
||||
bsLine['sell_cut'][i] = 0
|
||||
|
||||
if sell_price < 1:
|
||||
buy_ymd, buy_price, buy_count, buy_type, buy_cut = self.buySell_Daily.getBuyPrice(ticker, data, i, bsLine)
|
||||
|
||||
bsLine['buy_ymd'][i] = buy_ymd
|
||||
bsLine['buy_price'][i] = buy_price
|
||||
bsLine['buy_count'][i] = buy_count
|
||||
bsLine['buy_type'][i] = buy_type
|
||||
bsLine['buy_cut'][i] = buy_cut
|
||||
|
||||
return bsLine
|
||||
|
||||
|
||||
# 후보 찾기
|
||||
def findCandidates(self, outPath):
|
||||
buy_stock_list = []
|
||||
|
||||
stockTableName = 'stock'
|
||||
fnguideTableName = 'fnguide'
|
||||
|
||||
conn = sqlite3.connect(self.stockFileName)
|
||||
cursor = conn.cursor()
|
||||
|
||||
cursor.execute('SELECT distinct code, name FROM ' + stockTableName + ' order by code')
|
||||
#cursor.execute('select CODE, NAME, max(ymd) as ymd from ' + fnguideTableName + ' where type != "E" group by 1 order by total_assets desc')
|
||||
items = cursor.fetchall()
|
||||
|
||||
cursor.close()
|
||||
conn.close()
|
||||
|
||||
|
||||
for idx, item in enumerate(items):
|
||||
CODE = item[0]
|
||||
NAME = item[1]
|
||||
ticker = {'ticker_code': CODE, 'ticker_name': NAME, 'unit': 0, 'MAX_BUY': 10000, 'BUY_INFO': {'buy_list': []}}
|
||||
print("#", idx, ", CODE: ", CODE, ", NAME: ", NAME)
|
||||
|
||||
stock_daily, ci = self.getStockData(CODE)
|
||||
|
||||
bsLine = self.checkTransaction(ticker, stock_daily, ci)
|
||||
|
||||
if bsLine['buy_ymd'][ci-1] is not None:
|
||||
top = "0"
|
||||
if CODE in self.topCompany:
|
||||
top = str(self.topCompany[CODE][0])
|
||||
|
||||
# 거래량이 10만 이상이고, 종가가 1천원 이상인지 체크 (https://happpy-rich.tistory.com/94)
|
||||
if stock_daily['volume'][ci-1] > 100000 and stock_daily['close'][ci-1] > 1000:
|
||||
# 종목 상태 체크 분석
|
||||
|
||||
self.writeFile(outPath, CODE, NAME, top, stock_daily, bsLine)
|
||||
buy_stock_list.append({'CODE': CODE, 'NAME': NAME})
|
||||
|
||||
buy_stock_str = ''
|
||||
for i, item in enumerate(buy_stock_list):
|
||||
buy_stock_str += str(i + 1) + ". " + item['CODE'] + "(" + item['NAME'] + ")\n"
|
||||
self.bot.sendMsg("{}".format(buy_stock_str))
|
||||
|
||||
return
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
start = time.time()
|
||||
PROJECT_HOME = os.path.join(os.path.dirname(os.path.join(os.path.dirname(os.path.join(os.path.dirname(__file__))))))
|
||||
|
||||
RESOURCE_PATH = os.path.join(PROJECT_HOME, 'resources')
|
||||
analyzerSqlite = AnalyzerSqlite(RESOURCE_PATH)
|
||||
|
||||
|
||||
# HTML 출력
|
||||
outPath = os.path.join(PROJECT_HOME, "resources", "analysis")
|
||||
if not os.path.isdir(outPath):
|
||||
os.mkdir(outPath)
|
||||
day = datetime.today().strftime("%Y%m%d")
|
||||
before_7_day = datetime.today() + relativedelta(days=-7)
|
||||
dayList = os.listdir(outPath)
|
||||
for dayDir in dayList:
|
||||
if dayDir[0] != '.' and dayDir < before_7_day.strftime("%Y%m%d"):
|
||||
if os.path.exists(os.path.join(outPath, dayDir)) and os.path.isdir(os.path.join(outPath, dayDir)):
|
||||
shutil.rmtree(os.path.join(outPath, dayDir))
|
||||
|
||||
outPath = os.path.join(outPath, day)
|
||||
|
||||
if os.path.isdir(outPath):
|
||||
shutil.rmtree(outPath)
|
||||
os.mkdir(outPath)
|
||||
print("print to Html...")
|
||||
|
||||
analyzerSqlite.findCandidates(outPath)
|
||||
|
||||
print("time : %6.2f 초" % (time.time() - start))
|
||||
print("done...")
|
||||
@@ -1,571 +0,0 @@
|
||||
# https://bibot.tistory.com/63
|
||||
# https://nonmeyet.tistory.com/entry/Python-TALib%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-%EB%B9%84%ED%8A%B8%EC%BD%94%EC%9D%B8%EC%A3%BC%EA%B0%80%EA%B8%B0%EC%88%A0%EB%B6%84%EC%84%9D-%EB%B3%B4%EC%A1%B0%EC%A7%80%ED%91%9C-%EC%B6%94%EA%B0%80
|
||||
# https://lunadaddy.tistory.com/122
|
||||
# https://wikidocs.net/186885
|
||||
|
||||
import os
|
||||
import numpy as np
|
||||
np.seterr(divide='ignore', invalid='ignore')
|
||||
import sqlite3
|
||||
# https://www.lfd.uci.edu/~gohlke/pythonlibs/#ta-lib
|
||||
# https://lunadaddy.tistory.com/122
|
||||
import talib
|
||||
import pandas as pd
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from stock.analysis.IchimokuCloud import IchimokuCloud
|
||||
from sklearn.preprocessing import StandardScaler
|
||||
|
||||
class JSDPattern:
|
||||
stockFileName = None
|
||||
ichimokuCloud = None
|
||||
scaler = None
|
||||
|
||||
def __init__(self, stockFileName=None):
|
||||
self.stockFileName = stockFileName
|
||||
|
||||
self.ichimokuCloud = IchimokuCloud()
|
||||
self.scaler = StandardScaler()
|
||||
return
|
||||
|
||||
def makeTickData(self, data, mins=1):
|
||||
result = {
|
||||
"ymd": [],
|
||||
"open": [], "close": [], "high": [], "low": [], "volume": [], "volume_up": [], "volume_down": [], "volume_updown_diff": []
|
||||
}
|
||||
|
||||
for i in range(mins, len(data['ymd'])+1, mins):
|
||||
result["ymd"].append(data['ymd'][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["volume"].append(data['volume'][i-1])
|
||||
|
||||
if data['open'][i-1] < data['close'][i-1]:
|
||||
result["volume_up"].append(data['volume'][i-1])
|
||||
result["volume_down"].append(0)
|
||||
elif data['close'][i-1] < data['open'][i-1]:
|
||||
result["volume_down"].append(-1*data['volume'][i-1])
|
||||
result["volume_up"].append(0)
|
||||
else:
|
||||
result["volume_up"].append(0)
|
||||
result["volume_down"].append(0)
|
||||
|
||||
up = [data['volume'][i - mins + c] for c in range(len(data['volume'][i - mins: i])) if data['close'][i - mins + c] < data['open'][i - mins + c]]
|
||||
down = [data['volume'][i - mins + c] for c in range(len(data['volume'][i - mins: i])) if data['close'][i - mins + c] < data['open'][i - mins + c]]
|
||||
result["volume_updown_diff"].append(sum(up) - sum(down))
|
||||
|
||||
return result
|
||||
|
||||
def append(self, df=None, result=None):
|
||||
data = {
|
||||
"ymd": [],
|
||||
"open": [], "close": [], "high": [], "low": [], "volume": []
|
||||
}
|
||||
|
||||
if result is not None:
|
||||
for i in range(len(result['ymd'])):
|
||||
data['ymd'].append(result['ymd'][i])
|
||||
data['open'].append(result['open'][i])
|
||||
data['close'].append(result['close'][i])
|
||||
data['high'].append(result['high'][i])
|
||||
data['low'].append(result['low'][i])
|
||||
data['volume'].append(result['volume'][i])
|
||||
|
||||
if df is not None:
|
||||
for i in range(len(df)):
|
||||
data['ymd'].append(df.index[i])
|
||||
data['open'].append(df['open'][i])
|
||||
data['close'].append(df['close'][i])
|
||||
data['high'].append(df['high'][i])
|
||||
data['low'].append(df['low'][i])
|
||||
data['volume'].append(df['volume'][i])
|
||||
|
||||
return data
|
||||
|
||||
def getDBData(self, stock_code, day, get_days=14):
|
||||
|
||||
table = 'stock'
|
||||
|
||||
conn = sqlite3.connect(self.stockFileName)
|
||||
cursor = conn.cursor()
|
||||
|
||||
result = {"ymd": [], "open": [], "close": [], "high": [], "low": [], "volume": []}
|
||||
for i in range(get_days, -1, -1):
|
||||
this_day = (datetime.strptime(day, '%Y%m%d') - timedelta(i)).strftime('%Y.%m.%d')
|
||||
cursor.execute('SELECT ymd, open, high, low, close, volume FROM ' + table + ' WHERE CODE=? and ymd=? order by ymd', (stock_code, this_day,))
|
||||
|
||||
db_result = cursor.fetchall()
|
||||
for rows in db_result:
|
||||
ymd = datetime.strptime(rows[0], '%Y.%m.%d') # hts.날짜
|
||||
open = rows[1] # hts.시가
|
||||
high = rows[2] # hts.고가
|
||||
low = rows[3] # hts.저가
|
||||
close = rows[4] # hts.종가
|
||||
vol = rows[5] # hts.거래량
|
||||
|
||||
result["ymd"].append(ymd)
|
||||
result["open"].append(float(open))
|
||||
result["close"].append(float(close))
|
||||
result["high"].append(float(high))
|
||||
result["low"].append(float(low))
|
||||
result["volume"].append(float(vol))
|
||||
|
||||
cursor.close()
|
||||
conn.close()
|
||||
|
||||
return result
|
||||
|
||||
def getCoinData(self, ticker, ymd=None, get_days=14):
|
||||
result = self.getDBData(ticker, ymd, get_days=get_days)
|
||||
data = self.append(df=None, result=result)
|
||||
|
||||
return data
|
||||
|
||||
def is_Support(self, low, i, observation_time=5):
|
||||
# https://sine-qua-none.tistory.com/198
|
||||
|
||||
# c1 = df.Low[i] < df.Low[i - 1] < df.Low[i - 2] < df.Low[i - 3]
|
||||
# c2 = df.Low[i] < df.Low[i + 1] < df.Low[i + 2] < df.Low[i + 3]
|
||||
# return c1 & c2
|
||||
|
||||
#if low[i] == np.min(low[i - 2*self.observation_time:i + 1]):
|
||||
if low[i] == np.min(low[i - observation_time:i + observation_time + 1]):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def is_Resistance(self, high, i, observation_time=5):
|
||||
# https://sine-qua-none.tistory.com/198
|
||||
|
||||
# c1 = df.High[i] > df.High[i - 1] > df.High[i - 2] > df.High[i - 3]
|
||||
# c2 = df.High[i] > df.High[i + 1] > df.High[i + 2] > df.High[i + 3]
|
||||
# return c1 & c2
|
||||
# if df['high'][i] == np.max(df['high'][i - self.observation_time:i + self.observation_time + 1]):
|
||||
#if high[i] == np.max(high[i - 2*self.observation_time:i + 1]):
|
||||
if high[i] == np.max(high[i - observation_time:i + observation_time + 1]):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def getDiff_Rate(self, price1, price2, duration=1440, move=None):
|
||||
# price1: close, price2: laggingSpan_27
|
||||
diff = [0 for i in range(len(price1))]
|
||||
diff_rate = [0 for i in range(len(price1))]
|
||||
|
||||
for i in range(0, len(price1)):
|
||||
if price1[i] is not None and price2[i] is not None:
|
||||
diff[i] = price1[i] - price2[i]
|
||||
else:
|
||||
diff[i] = None
|
||||
|
||||
if len(price1) < duration:
|
||||
duration = 52
|
||||
|
||||
for i in range(0, len(price1)):
|
||||
|
||||
if duration <= i:
|
||||
l = [d for d in diff[i - duration:i + 1] if d is not None and 0 < d]
|
||||
if 0 < len(l):
|
||||
min_v_p = np.min(l)
|
||||
else:
|
||||
min_v_p = 0
|
||||
l = [d for d in diff[i - duration:i + 1] if d is not None and 0 < d]
|
||||
if 0 < len(l):
|
||||
max_v_p = np.max(l)
|
||||
else:
|
||||
max_v_p = 0
|
||||
l = [d for d in diff[i - duration:i + 1] if d is not None and d < 0]
|
||||
if 0 < len(l):
|
||||
min_v_m = np.min(l)
|
||||
else:
|
||||
min_v_m = 0
|
||||
l = [d for d in diff[i - duration:i + 1] if d is not None and d < 0]
|
||||
if 0 < len(l):
|
||||
max_v_m = np.max(l)
|
||||
else:
|
||||
max_v_m = 0
|
||||
|
||||
if diff[i] is not None:
|
||||
if 0 <= diff[i]:
|
||||
if max_v_p - min_v_p == 0:
|
||||
diff_rate[i] = 0
|
||||
else:
|
||||
diff_rate[i] = (diff[i] - min_v_p) / (max_v_p - min_v_p)
|
||||
else:
|
||||
if max_v_m - min_v_m == 0:
|
||||
diff_rate[i] = 0
|
||||
else:
|
||||
diff_rate[i] = ((diff[i] - min_v_m) / (max_v_m - min_v_m)) - 1
|
||||
else:
|
||||
diff_rate[i] = None
|
||||
|
||||
return diff, diff_rate
|
||||
|
||||
def analyze(self, result, mins=1):
|
||||
result["volume"] = [result["volume"][i] if 0 < result["volume"][i] else 1 for i in range(len(result["volume"]))]
|
||||
# 기본 캔들 정보
|
||||
open_df = pd.DataFrame(result["open"])
|
||||
close_df = pd.DataFrame(result["close"])
|
||||
high_df = pd.DataFrame(result["high"])
|
||||
low_df = pd.DataFrame(result["low"])
|
||||
volume_df = pd.DataFrame(result["volume"])
|
||||
|
||||
# 중복 제거
|
||||
ymd_df = pd.DataFrame(result["ymd"])
|
||||
data_dup = pd.concat([ymd_df, open_df, close_df, high_df, low_df, volume_df], axis=1)
|
||||
data_dup.columns = ["ymd", "open", "close", "high", "low", "volume"]
|
||||
data_dup.index = pd.DatetimeIndex(result["ymd"])
|
||||
data_dup_sorted = data_dup.sort_index(ascending=True)
|
||||
data_dup_sorted = data_dup_sorted.drop_duplicates()
|
||||
|
||||
ymd_df = data_dup_sorted["ymd"]
|
||||
open_df = data_dup_sorted["open"]
|
||||
close_df = data_dup_sorted["close"]
|
||||
high_df = data_dup_sorted["high"]
|
||||
low_df = data_dup_sorted["low"]
|
||||
volume_df = data_dup_sorted["volume"]
|
||||
|
||||
ymd = ymd_df.tolist()
|
||||
open = open_df.tolist()
|
||||
close = close_df.tolist()
|
||||
high = high_df.tolist()
|
||||
low = low_df.tolist()
|
||||
volume = volume_df.tolist()
|
||||
|
||||
# ichimokuCloud
|
||||
df = pd.concat([ymd_df, open_df, close_df, high_df, low_df, volume_df], axis=1)
|
||||
column_names = ['DATE', 'open', 'close', 'high', 'low', 'volume']
|
||||
df.columns = column_names
|
||||
c, b, l, s = 9, 26, 52, 26
|
||||
# 1. 전환선 = (과거 9일 동안 최고가 + 최저가) / 2
|
||||
# 당일을 포함한 9일 동안의 최고가와 최저가의 중간 값을 평균으로 나타낸다.
|
||||
changeLine = (df.high.rolling(c).max() + df.low.rolling(c).min()) / 2
|
||||
# 2. 기준선 = 과거 26일 동안 최고가 + 최저가) / 2
|
||||
# 당일을 포함한 26일 동안의 최고가와 최저가의 중간 값을 평균으로 나타낸다.
|
||||
baseLine = (df.high.rolling(b).max() + df.low.rolling(b).min()) / 2
|
||||
|
||||
# 3. 후행스팬 = 현재 close가격의 26일전 반영
|
||||
laggingSpan = [df.close.values[i + s] for i in range(len(df.close) - s)]
|
||||
laggingSpan += [None for i in range(s)]
|
||||
laggingSpan = np.array(laggingSpan)
|
||||
|
||||
# 4. 선행스팬 1 = ((기준선 + 전환선) / 2)를 26일 선행하여 배치
|
||||
# 전환선과 기준선의 평균값을 구해 당일 포함 26일 앞으로 이동시킨 선 (중-단기 구간의 힘을 보여줌)
|
||||
tmp_leadingSpan1 = (changeLine + baseLine) / 2
|
||||
""" S: 26일 선행시킴 """
|
||||
leadingSpan1 = list(tmp_leadingSpan1.values)
|
||||
for i in range(b - 1):
|
||||
leadingSpan1.insert(0, None)
|
||||
""" E: 26일 선행시킴 """
|
||||
|
||||
# 5. 선행스팬 2 = ((최근 52일 동안 최고가 + 최저가) / 2)를 26일 선행하여 배치
|
||||
# 당일을 포함한 52일 동안의 최고가와 최저가의 평균을 26일 앞으로 이동시킨 선 (장기으로 형성된 선이기 때문에 가장 느리게 변함)
|
||||
tmp_leadingSpan2 = (df.high.rolling(l).max() + df.low.rolling(l).min()) / 2
|
||||
""" S: 52일 선행시킴 """
|
||||
leadingSpan2 = list(tmp_leadingSpan2.values)
|
||||
for i in range(l - 1):
|
||||
leadingSpan2.insert(0, None)
|
||||
""" S: 52일 선행시킴 """
|
||||
|
||||
baseLine = baseLine.tolist()
|
||||
changeLine = changeLine.tolist()
|
||||
laggingSpan = list(laggingSpan)
|
||||
current_index = len(ymd)
|
||||
for i in range(51):
|
||||
if len(ymd) < len(leadingSpan2):
|
||||
if mins==1440:
|
||||
ymd.append(ymd[-1] + timedelta(days=1))
|
||||
else:
|
||||
ymd.append(ymd[-1] + timedelta(minutes=1))
|
||||
if len(open) < len(leadingSpan2):
|
||||
open.append(None)
|
||||
if len(close) < len(leadingSpan2):
|
||||
close.append(None)
|
||||
if len(high) < len(leadingSpan2):
|
||||
high.append(None)
|
||||
if len(low) < len(leadingSpan2):
|
||||
low.append(None)
|
||||
if len(volume) < len(leadingSpan2):
|
||||
volume.append(None)
|
||||
if len(baseLine) < len(leadingSpan2):
|
||||
baseLine.append(None)
|
||||
if len(changeLine) < len(leadingSpan2):
|
||||
changeLine.append(None)
|
||||
if len(laggingSpan) < len(leadingSpan2):
|
||||
laggingSpan.append(None)
|
||||
for i in range(26):
|
||||
if len(leadingSpan1) < len(leadingSpan2):
|
||||
leadingSpan1.append(leadingSpan1[-1])
|
||||
|
||||
# 9일 신고가
|
||||
new_high_9 = [0 for c in range(8)] + [1 if (changeLine[c-1] is not None and changeLine[c] is not None and changeLine[c-1] < changeLine[c]) and None not in close[c-8:c+1] and max(close[c-8:c]) < close[c] else 0 for c in range(8, len(close))]
|
||||
# 26일 신고가
|
||||
new_high_26 = [0 for c in range(25)] + [1 if (baseLine[c-1] is not None and baseLine[c] is not None and baseLine[c-1] < baseLine[c]) and None not in close[c-8:c+1] and max(close[c-25:c]) < close[c] else 0 for c in range(25, len(close))]
|
||||
# 33일 신고가
|
||||
new_high_33 = [0 for c in range(32)] + [1 if (leadingSpan1[c-1] is not None and leadingSpan1[c] is not None and leadingSpan1[c-1] < leadingSpan1[c]) and None not in close[c-8:c+1] and max(close[c-32:c]) < close[c] else 0 for c in range(32, len(close))]
|
||||
# 52일 신고가
|
||||
new_high_52 = [0 for c in range(51)] + [1 if (leadingSpan2[c-1] is not None and leadingSpan2[c] is not None and leadingSpan2[c-1] < leadingSpan2[c]) and None not in close[c-8:c+1] and max(close[c-51:c]) < close[c] else 0 for c in range(51, len(close))]
|
||||
|
||||
# 9일 신저가
|
||||
new_low_9 = [0 for c in range(8)] + [1 if (changeLine[c-1] is not None and changeLine[c] is not None and changeLine[c-1] < changeLine[c]) and None not in close[c-8:c+1] and close[c-9] < min(close[c-8:c+1]) else 0 for c in range(8, len(close))]
|
||||
# 26일 신저가
|
||||
new_low_26 = [0 for c in range(25)] + [1 if (baseLine[c-1] is not None and baseLine[c] is not None and baseLine[c-1] < baseLine[c]) and None not in close[c-8:c+1] and close[c-26] < min(close[c-25:c+1]) else 0 for c in range(25, len(close))]
|
||||
# 33일 신저가
|
||||
new_low_33 = [0 for c in range(32)] + [1 if (leadingSpan1[c-1] is not None and leadingSpan1[c] is not None and leadingSpan1[c-1] < leadingSpan1[c]) and None not in close[c-8:c+1] and close[c-33] < min(close[c-32:c+1]) else 0 for c in range(32, len(close))]
|
||||
# 52일 신저가
|
||||
new_low_52 = [0 for c in range(51)] + [1 if (leadingSpan2[c-1] is not None and leadingSpan2[c] is not None and leadingSpan2[c-1] < leadingSpan2[c]) and None not in close[c-8:c+1] and close[c-52] < min(close[c-51:c+1]) else 0 for c in range(51, len(close))]
|
||||
|
||||
|
||||
# 이동 평균
|
||||
close_df = pd.DataFrame(close)
|
||||
avg5 = list(np.reshape(close_df.ewm(5).mean().values, -1))
|
||||
avg10 = list(np.reshape(close_df.ewm(10).mean().values, -1))
|
||||
avg20 = list(np.reshape(close_df.ewm(20).mean().values, -1))
|
||||
avg60 = list(np.reshape(close_df.ewm(60).mean().values, -1))
|
||||
avg90 = list(np.reshape(close_df.ewm(90).mean().values, -1))
|
||||
avg120 = list(np.reshape(close_df.ewm(120).mean().values, -1))
|
||||
avg240 = list(np.reshape(close_df.ewm(240).mean().values, -1))
|
||||
avg360 = list(np.reshape(close_df.ewm(360).mean().values, -1))
|
||||
avg480 = list(np.reshape(close_df.ewm(480).mean().values, -1))
|
||||
avg720 = list(np.reshape(close_df.ewm(720).mean().values, -1))
|
||||
avg1440 = list(np.reshape(close_df.ewm(1440).mean().values, -1))
|
||||
avg2880 = list(np.reshape(close_df.ewm(2880).mean().values, -1))
|
||||
|
||||
np_high, np_low, np_close = np.array(high, dtype=np.float64), np.array(low, dtype=np.float64), np.array(close, dtype=np.float64)
|
||||
slowk_12_df, slowd_12_df = talib.STOCH(np_high, np_low, np_close, fastk_period=12, slowk_period=5, slowk_matype=0, slowd_period=5, slowd_matype=0)
|
||||
slowk_26_df, slowd_26_df = talib.STOCH(np_high, np_low, np_close, fastk_period=26, slowk_period=16, slowk_matype=0, slowd_period=16, slowd_matype=0)
|
||||
slowk_52_df, slowd_52_df = talib.STOCH(np_high, np_low, np_close, fastk_period=52, slowk_period=32, slowk_matype=0, slowd_period=32, slowd_matype=0)
|
||||
|
||||
|
||||
# 최고/최저 위치
|
||||
loc_240 = [None for i in range(len(close))]
|
||||
for i in range(240, len(close)):
|
||||
min_v = np.min(result["close"][i-239:i+1])
|
||||
max_v = np.max(result["close"][i-239:i+1])
|
||||
if close[i] is not None:
|
||||
loc_240[i] = ((close[i] - min_v) / (max_v - min_v))
|
||||
else:
|
||||
loc_240[i] = None
|
||||
|
||||
loc_240 = pd.DataFrame(loc_240)
|
||||
loc_240_k = loc_240.to_numpy().reshape(-1)
|
||||
loc_240_d = loc_240.rolling(20).mean()
|
||||
loc_240_s = loc_240.rolling(60).mean()
|
||||
loc_240_d = loc_240_d.to_numpy().reshape(-1)
|
||||
loc_240_s = loc_240_s.to_numpy().reshape(-1)
|
||||
|
||||
# 볼린저 밴드
|
||||
n, t = 10, 2
|
||||
max_10 = close_df.rolling(window=n).mean()
|
||||
stddev_10 = close_df.rolling(window=n).std()
|
||||
upper_10 = max_10 + (stddev_10 * t) # 상단 볼리저 밴드
|
||||
lower_10 = max_10 - (stddev_10 * t) # 하단 볼리저 밴드
|
||||
middle_10 = (upper_10 + lower_10) / 2
|
||||
upper_10 = list(np.reshape(upper_10.values, -1))
|
||||
lower_10 = list(np.reshape(lower_10.values, -1))
|
||||
middle_10 = list(np.reshape(middle_10.values, -1))
|
||||
|
||||
n, t = 20, 2
|
||||
max_20 = close_df.rolling(window=n).mean()
|
||||
stddev_20 = close_df.rolling(window=n).std()
|
||||
upper_20 = max_20 + (stddev_20 * t) # 상단 볼리저 밴드
|
||||
lower_20 = max_20 - (stddev_20 * t) # 하단 볼리저 밴드
|
||||
middle_20 = (upper_20 + lower_20) / 2
|
||||
upper_20 = list(np.reshape(upper_20.values, -1))
|
||||
lower_20 = list(np.reshape(lower_20.values, -1))
|
||||
middle_20 = list(np.reshape(middle_20.values, -1))
|
||||
|
||||
duration = 1440
|
||||
if mins == 1440:
|
||||
duration = 360
|
||||
laggingSpan_close_diff, laggingSpan_close_diff_rate = self.getDiff_Rate(laggingSpan, close, duration=duration)
|
||||
laggingSpan_changeLine_diff, laggingSpan_changeLine_diff_rate = self.getDiff_Rate(laggingSpan, changeLine, duration=duration)
|
||||
laggingSpan_baseLine_diff, laggingSpan_baseLine_diff_rate = self.getDiff_Rate(laggingSpan, baseLine, duration=duration)
|
||||
laggingSpan_leadingSpan1_diff, laggingSpan_leadingSpan1_diff_rate = self.getDiff_Rate(laggingSpan, leadingSpan1, duration=duration)
|
||||
laggingSpan_leadingSpan2_diff, laggingSpan_leadingSpan2_diff_rate = self.getDiff_Rate(laggingSpan, leadingSpan2, duration=duration)
|
||||
laggingSpan_avg60_diff, laggingSpan_avg60_diff_rate = self.getDiff_Rate(laggingSpan, avg60, duration=duration)
|
||||
laggingSpan_lower10_diff, laggingSpan_lower10_diff_rate = self.getDiff_Rate(laggingSpan, lower_10, duration=duration)
|
||||
laggingSpan_middle10_diff, laggingSpan_middle10_diff_rate = self.getDiff_Rate(laggingSpan, middle_10, duration=duration)
|
||||
laggingSpan_upper10_diff, laggingSpan_upper10_diff_rate = self.getDiff_Rate(laggingSpan, upper_10, duration=duration)
|
||||
laggingSpan_lower20_diff, laggingSpan_lower20_diff_rate = self.getDiff_Rate(laggingSpan, lower_20, duration=duration)
|
||||
laggingSpan_middle20_diff, laggingSpan_middle20_diff_rate = self.getDiff_Rate(laggingSpan, middle_20, duration=duration)
|
||||
laggingSpan_upper20_diff, laggingSpan_upper20_diff_rate = self.getDiff_Rate(laggingSpan, upper_20, duration=duration)
|
||||
baseLine_close_diff, baseLine_close_diff_rate = self.getDiff_Rate(baseLine, close, duration=duration)
|
||||
changeLine_close_diff, changeLine_close_diff_rate = self.getDiff_Rate(changeLine, close, duration=duration)
|
||||
changeLine_baseLine_diff, changeLine_baseLine_diff_rate = self.getDiff_Rate(changeLine, baseLine, duration=duration)
|
||||
changeLine_leadingSpan1_diff, changeLine_leadingSpan1_diff_rate = self.getDiff_Rate(changeLine, leadingSpan1, duration=duration)
|
||||
leadingSpan1_leadingSpan2_diff, leadingSpan1_leadingSpan2_diff_rate = self.getDiff_Rate(leadingSpan1, leadingSpan2, duration=duration)
|
||||
|
||||
|
||||
df_list = [
|
||||
pd.DataFrame(ymd),
|
||||
pd.DataFrame(open), pd.DataFrame(close), pd.DataFrame(high), pd.DataFrame(low), pd.DataFrame(volume),
|
||||
pd.DataFrame(changeLine), pd.DataFrame(baseLine), pd.DataFrame(laggingSpan), pd.DataFrame(leadingSpan1), pd.DataFrame(leadingSpan2),
|
||||
|
||||
pd.DataFrame(laggingSpan_close_diff),
|
||||
pd.DataFrame(laggingSpan_changeLine_diff),
|
||||
pd.DataFrame(laggingSpan_baseLine_diff),
|
||||
pd.DataFrame(laggingSpan_leadingSpan1_diff),
|
||||
pd.DataFrame(laggingSpan_leadingSpan2_diff),
|
||||
pd.DataFrame(laggingSpan_avg60_diff),
|
||||
pd.DataFrame(laggingSpan_lower10_diff),
|
||||
pd.DataFrame(laggingSpan_middle10_diff),
|
||||
pd.DataFrame(laggingSpan_upper10_diff),
|
||||
pd.DataFrame(laggingSpan_lower20_diff),
|
||||
pd.DataFrame(laggingSpan_middle20_diff),
|
||||
pd.DataFrame(laggingSpan_upper20_diff),
|
||||
pd.DataFrame(baseLine_close_diff),
|
||||
pd.DataFrame(changeLine_close_diff),
|
||||
pd.DataFrame(changeLine_baseLine_diff),
|
||||
pd.DataFrame(changeLine_leadingSpan1_diff),
|
||||
pd.DataFrame(leadingSpan1_leadingSpan2_diff),
|
||||
|
||||
pd.DataFrame(laggingSpan_close_diff_rate),
|
||||
pd.DataFrame(laggingSpan_changeLine_diff_rate),
|
||||
pd.DataFrame(laggingSpan_baseLine_diff_rate),
|
||||
pd.DataFrame(laggingSpan_leadingSpan1_diff_rate),
|
||||
pd.DataFrame(laggingSpan_leadingSpan2_diff_rate),
|
||||
pd.DataFrame(laggingSpan_avg60_diff_rate),
|
||||
pd.DataFrame(laggingSpan_lower10_diff_rate),
|
||||
pd.DataFrame(laggingSpan_middle10_diff_rate),
|
||||
pd.DataFrame(laggingSpan_upper10_diff_rate),
|
||||
pd.DataFrame(laggingSpan_lower20_diff_rate),
|
||||
pd.DataFrame(laggingSpan_middle20_diff_rate),
|
||||
pd.DataFrame(laggingSpan_upper20_diff_rate),
|
||||
pd.DataFrame(baseLine_close_diff_rate),
|
||||
pd.DataFrame(changeLine_close_diff_rate),
|
||||
pd.DataFrame(changeLine_baseLine_diff_rate),
|
||||
pd.DataFrame(changeLine_leadingSpan1_diff_rate),
|
||||
pd.DataFrame(leadingSpan1_leadingSpan2_diff_rate),
|
||||
|
||||
pd.DataFrame(loc_240_k), pd.DataFrame(loc_240_d), pd.DataFrame(loc_240_s),
|
||||
|
||||
pd.DataFrame(avg5), pd.DataFrame(avg10), pd.DataFrame(avg20), pd.DataFrame(avg60), pd.DataFrame(avg90), pd.DataFrame(avg120), pd.DataFrame(avg240), pd.DataFrame(avg360), pd.DataFrame(avg480), pd.DataFrame(avg720), pd.DataFrame(avg1440), pd.DataFrame(avg2880),
|
||||
pd.DataFrame(upper_10), pd.DataFrame(lower_10), pd.DataFrame(middle_10),
|
||||
pd.DataFrame(upper_20), pd.DataFrame(lower_20), pd.DataFrame(middle_20),
|
||||
|
||||
pd.DataFrame(new_high_9), pd.DataFrame(new_high_26), pd.DataFrame(new_high_33), pd.DataFrame(new_high_52),
|
||||
pd.DataFrame(new_low_9), pd.DataFrame(new_low_26), pd.DataFrame(new_low_33), pd.DataFrame(new_low_52),
|
||||
pd.DataFrame(slowk_12_df), pd.DataFrame(slowd_12_df),
|
||||
pd.DataFrame(slowk_26_df), pd.DataFrame(slowd_26_df),
|
||||
pd.DataFrame(slowk_52_df), pd.DataFrame(slowd_52_df),
|
||||
|
||||
]
|
||||
|
||||
data = pd.concat(df_list, axis=1)
|
||||
column_names = [
|
||||
'ymd',
|
||||
'open', 'close', 'high', 'low', 'volume',
|
||||
'changeLine', 'baseLine', 'laggingSpan', 'leadingSpan1', 'leadingSpan2',
|
||||
|
||||
'laggingSpan_close_diff',
|
||||
'laggingSpan_changeLine_diff',
|
||||
'laggingSpan_baseLine_diff',
|
||||
'laggingSpan_leadingSpan1_diff',
|
||||
'laggingSpan_leadingSpan2_diff',
|
||||
'laggingSpan_avg60_diff',
|
||||
'laggingSpan_lower10_diff',
|
||||
'laggingSpan_middle10_diff',
|
||||
'laggingSpan_upper10_diff',
|
||||
'laggingSpan_lower20_diff',
|
||||
'laggingSpan_middle20_diff',
|
||||
'laggingSpan_upper20_diff',
|
||||
'baseLine_close_diff',
|
||||
'changeLine_close_diff',
|
||||
'changeLine_baseLine_diff',
|
||||
'changeLine_leadingSpan1_diff',
|
||||
'leadingSpan1_leadingSpan2_diff',
|
||||
|
||||
'laggingSpan_close_diff_rate',
|
||||
'laggingSpan_changeLine_diff_rate',
|
||||
'laggingSpan_baseLine_diff_rate',
|
||||
'laggingSpan_leadingSpan1_diff_rate',
|
||||
'laggingSpan_leadingSpan2_diff_rate',
|
||||
'laggingSpan_avg60_diff_rate',
|
||||
'laggingSpan_lower10_diff_rate',
|
||||
'laggingSpan_middle10_diff_rate',
|
||||
'laggingSpan_upper10_diff_rate',
|
||||
'laggingSpan_lower20_diff_rate',
|
||||
'laggingSpan_middle20_diff_rate',
|
||||
'laggingSpan_upper20_diff_rate',
|
||||
'baseLine_close_diff_rate',
|
||||
'changeLine_close_diff_rate',
|
||||
'changeLine_baseLine_diff_rate',
|
||||
'changeLine_leadingSpan1_diff_rate',
|
||||
'leadingSpan1_leadingSpan2_diff_rate',
|
||||
|
||||
'loc_240_k', 'loc_240_d', 'loc_240_s',
|
||||
|
||||
'avg5', 'avg10', 'avg20', 'avg60', 'avg90', 'avg120', 'avg240', 'avg360', 'avg480', 'avg720', 'avg1440', 'avg2880',
|
||||
|
||||
'upper_10', 'lower_10', 'middle_10',
|
||||
'upper_20', 'lower_20', 'middle_20',
|
||||
|
||||
'new_high_9', 'new_high_26', 'new_high_33', 'new_high_52',
|
||||
'new_low_9', 'new_low_26', 'new_low_33', 'new_low_52',
|
||||
|
||||
'slowk_12', 'slowd_12',
|
||||
'slowk_26', 'slowd_26',
|
||||
'slowk_52', 'slowd_52',
|
||||
]
|
||||
data.columns = column_names
|
||||
data.index = pd.DatetimeIndex(ymd)
|
||||
|
||||
return data, current_index
|
||||
|
||||
def getData(self, ticker, mins=None, ymd=None, get_days=14):
|
||||
if ymd is None:
|
||||
result = self.getCoinData(ticker, mins=mins, get_days=get_days)
|
||||
else:
|
||||
result = self.getCoinData(ticker, mins=mins, ymd=ymd, get_days=get_days)
|
||||
|
||||
if len(result['ymd']) < 1:
|
||||
return None, None
|
||||
|
||||
#result_tic = self.makeTickData(result_m1, mins=minute)
|
||||
data, current_index = self.analyze(result, mins=mins)
|
||||
return data, current_index
|
||||
|
||||
def analyzePattern(self, data):
|
||||
# jSDPattern.analyzePattern(data)
|
||||
|
||||
data = data[['open', 'high', 'low', 'close', 'volume']].astype(float)
|
||||
pattern_names = talib.get_function_groups()['Pattern Recognition']
|
||||
pattern_results = {}
|
||||
for pattern in pattern_names:
|
||||
pattern_function = getattr(talib, pattern)
|
||||
result = pattern_function(data['open'].values, data['high'].values, data['low'].values, data['close'].values)
|
||||
if result[-1] != 0:
|
||||
pattern_results[pattern] = result[-1]
|
||||
|
||||
if len(pattern_results) > 0:
|
||||
for pattern, result in pattern_results.items():
|
||||
if result > 0:
|
||||
direction = "상승"
|
||||
else:
|
||||
direction = "하락"
|
||||
print(f"{pattern}: {direction}")
|
||||
else:
|
||||
print("인식된 차트 패턴이 없습니다.")
|
||||
|
||||
return
|
||||
|
||||
if __name__ == "__main__":
|
||||
def min_max_normalize(data):
|
||||
min_val = min(data)
|
||||
max_val = max(data)
|
||||
normalized_data = [(x - min_val) / (max_val - min_val) for x in data]
|
||||
return normalized_data
|
||||
|
||||
|
||||
# 예시 데이터
|
||||
original_data = [-4, -3, -2, -1, 0]
|
||||
normalized_data = min_max_normalize(original_data)
|
||||
print(np.asarray(normalized_data)-1)
|
||||
original_data = [0, 2,4,6,8,10]
|
||||
normalized_data = min_max_normalize(original_data)
|
||||
print(normalized_data)
|
||||
@@ -1,255 +0,0 @@
|
||||
# https://bibot.tistory.com/63
|
||||
# https://nonmeyet.tistory.com/entry/Python-TALib%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-%EB%B9%84%ED%8A%B8%EC%BD%94%EC%9D%B8%EC%A3%BC%EA%B0%80%EA%B8%B0%EC%88%A0%EB%B6%84%EC%84%9D-%EB%B3%B4%EC%A1%B0%EC%A7%80%ED%91%9C-%EC%B6%94%EA%B0%80
|
||||
# https://lunadaddy.tistory.com/122
|
||||
# https://wikidocs.net/186885
|
||||
|
||||
import os
|
||||
from scipy.signal import savgol_filter
|
||||
import numpy as np
|
||||
np.seterr(divide='ignore', invalid='ignore')
|
||||
# https://www.lfd.uci.edu/~gohlke/pythonlibs/#ta-lib
|
||||
# https://lunadaddy.tistory.com/122
|
||||
import talib
|
||||
import pandas as pd
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from stock.analysis.JSDPattern import JSDPattern
|
||||
|
||||
class JSDPattern_realtime (JSDPattern):
|
||||
|
||||
def __init__(self, stockFileName=None):
|
||||
super().__init__(stockFileName)
|
||||
return
|
||||
|
||||
def analyze(self, result):
|
||||
result["volume"] = [result["volume"][i] if 0 < result["volume"][i] else 1 for i in range(len(result["volume"]))]
|
||||
# 기본 캔들 정보
|
||||
open_df = pd.DataFrame(result["open"])
|
||||
close_df = pd.DataFrame(result["close"])
|
||||
high_df = pd.DataFrame(result["high"])
|
||||
low_df = pd.DataFrame(result["low"])
|
||||
volume_df = pd.DataFrame(result["volume"])
|
||||
|
||||
# 중복 제거
|
||||
ymd_df = pd.DataFrame(result["ymd"])
|
||||
data_dup = pd.concat([ymd_df, open_df, close_df, high_df, low_df, volume_df], axis=1)
|
||||
data_dup.columns = ["ymd", "open", "close", "high", "low", "volume"]
|
||||
data_dup.index = pd.DatetimeIndex(result["ymd"])
|
||||
data_dup_sorted = data_dup.sort_index(ascending=True)
|
||||
data_dup_sorted = data_dup_sorted.drop_duplicates()
|
||||
|
||||
ymd_df = data_dup_sorted["ymd"]
|
||||
open_df = data_dup_sorted["open"]
|
||||
close_df = data_dup_sorted["close"]
|
||||
high_df = data_dup_sorted["high"]
|
||||
low_df = data_dup_sorted["low"]
|
||||
volume_df = data_dup_sorted["volume"]
|
||||
|
||||
ymd = ymd_df.tolist()
|
||||
open = open_df.tolist()
|
||||
close = close_df.tolist()
|
||||
high = high_df.tolist()
|
||||
low = low_df.tolist()
|
||||
volume = volume_df.tolist()
|
||||
|
||||
# ichimokuCloud
|
||||
df = pd.concat([ymd_df, open_df, close_df, high_df, low_df, volume_df], axis=1)
|
||||
column_names = ['DATE', 'open', 'close', 'high', 'low', 'volume']
|
||||
df.columns = column_names
|
||||
c, b, l, s = 9, 26, 52, 26
|
||||
# 1. 전환선 = (과거 9일 동안 최고가 + 최저가) / 2
|
||||
# 당일을 포함한 9일 동안의 최고가와 최저가의 중간 값을 평균으로 나타낸다.
|
||||
changeLine = (df.high.rolling(c).max() + df.low.rolling(c).min()) / 2
|
||||
# 2. 기준선 = 과거 26일 동안 최고가 + 최저가) / 2
|
||||
# 당일을 포함한 26일 동안의 최고가와 최저가의 중간 값을 평균으로 나타낸다.
|
||||
baseLine = (df.high.rolling(b).max() + df.low.rolling(b).min()) / 2
|
||||
|
||||
# 3. 후행스팬 = 현재 close가격의 26일전 반영
|
||||
laggingSpan = [df.close.values[i + s] for i in range(len(df.close) - s)]
|
||||
laggingSpan += [None for i in range(s)]
|
||||
laggingSpan = np.array(laggingSpan)
|
||||
|
||||
# 4. 선행스팬 1 = ((기준선 + 전환선) / 2)를 26일 선행하여 배치
|
||||
# 전환선과 기준선의 평균값을 구해 당일 포함 26일 앞으로 이동시킨 선 (중-단기 구간의 힘을 보여줌)
|
||||
tmp_leadingSpan1 = (changeLine + baseLine) / 2
|
||||
""" S: 26일 선행시킴 """
|
||||
leadingSpan1 = list(tmp_leadingSpan1.values)
|
||||
for i in range(b - 1):
|
||||
leadingSpan1.insert(0, None)
|
||||
""" E: 26일 선행시킴 """
|
||||
|
||||
# 5. 선행스팬 2 = ((최근 52일 동안 최고가 + 최저가) / 2)를 26일 선행하여 배치
|
||||
# 당일을 포함한 52일 동안의 최고가와 최저가의 평균을 26일 앞으로 이동시킨 선 (장기으로 형성된 선이기 때문에 가장 느리게 변함)
|
||||
tmp_leadingSpan2 = (df.high.rolling(l).max() + df.low.rolling(l).min()) / 2
|
||||
""" S: 52일 선행시킴 """
|
||||
leadingSpan2 = list(tmp_leadingSpan2.values)
|
||||
for i in range(l - 1):
|
||||
leadingSpan2.insert(0, None)
|
||||
""" S: 52일 선행시킴 """
|
||||
|
||||
baseLine = baseLine.tolist()
|
||||
changeLine = changeLine.tolist()
|
||||
laggingSpan = list(laggingSpan)
|
||||
current_index = len(ymd)
|
||||
for i in range(51):
|
||||
if len(ymd) < len(leadingSpan2):
|
||||
ymd.append(ymd[-1] + timedelta(days=1))
|
||||
if len(open) < len(leadingSpan2):
|
||||
open.append(None)
|
||||
if len(close) < len(leadingSpan2):
|
||||
close.append(None)
|
||||
if len(high) < len(leadingSpan2):
|
||||
high.append(None)
|
||||
if len(low) < len(leadingSpan2):
|
||||
low.append(None)
|
||||
if len(volume) < len(leadingSpan2):
|
||||
volume.append(None)
|
||||
if len(baseLine) < len(leadingSpan2):
|
||||
baseLine.append(None)
|
||||
if len(changeLine) < len(leadingSpan2):
|
||||
changeLine.append(None)
|
||||
if len(laggingSpan) < len(leadingSpan2):
|
||||
laggingSpan.append(None)
|
||||
for i in range(26):
|
||||
if len(leadingSpan1) < len(leadingSpan2):
|
||||
leadingSpan1.append(leadingSpan1[-1])
|
||||
|
||||
# 9일 신고가
|
||||
new_high_9 = [0 for c in range(8)] + [1 if (changeLine[c-1] is not None and changeLine[c] is not None and changeLine[c-1] < changeLine[c]) and None not in close[c-8:c+1] and max(close[c-8:c]) < close[c] else 0 for c in range(8, len(close))]
|
||||
# 26일 신고가
|
||||
new_high_26 = [0 for c in range(25)] + [1 if (baseLine[c-1] is not None and baseLine[c] is not None and baseLine[c-1] < baseLine[c]) and None not in close[c-8:c+1] and max(close[c-25:c]) < close[c] else 0 for c in range(25, len(close))]
|
||||
|
||||
# 9일 신저가
|
||||
new_low_9 = [0 for c in range(8)] + [1 if (changeLine[c-1] is not None and changeLine[c] is not None and changeLine[c-1] < changeLine[c]) and None not in close[c-8:c+1] and close[c-9] < min(close[c-8:c+1]) else 0 for c in range(8, len(close))]
|
||||
# 26일 신저가
|
||||
new_low_26 = [0 for c in range(25)] + [1 if (baseLine[c-1] is not None and baseLine[c] is not None and baseLine[c-1] < baseLine[c]) and None not in close[c-8:c+1] and close[c-26] < min(close[c-25:c+1]) else 0 for c in range(25, len(close))]
|
||||
|
||||
|
||||
# 이동 평균
|
||||
close_df = pd.DataFrame(close)
|
||||
avg5 = list(np.reshape(close_df.ewm(5).mean().values, -1))
|
||||
avg10 = list(np.reshape(close_df.ewm(10).mean().values, -1))
|
||||
avg20 = list(np.reshape(close_df.ewm(20).mean().values, -1))
|
||||
avg60 = list(np.reshape(close_df.ewm(60).mean().values, -1))
|
||||
avg90 = list(np.reshape(close_df.ewm(90).mean().values, -1))
|
||||
avg120 = list(np.reshape(close_df.ewm(120).mean().values, -1))
|
||||
avg240 = list(np.reshape(close_df.ewm(240).mean().values, -1))
|
||||
avg360 = list(np.reshape(close_df.ewm(360).mean().values, -1))
|
||||
avg480 = list(np.reshape(close_df.ewm(480).mean().values, -1))
|
||||
|
||||
np_high, np_low, np_close = np.array(high, dtype=np.float64), np.array(low, dtype=np.float64), np.array(close, dtype=np.float64)
|
||||
slowk_12_df, slowd_12_df = talib.STOCH(np_high, np_low, np_close, fastk_period=12, slowk_period=5, slowk_matype=0, slowd_period=5, slowd_matype=0)
|
||||
slowk_26_df, slowd_26_df = talib.STOCH(np_high, np_low, np_close, fastk_period=26, slowk_period=16, slowk_matype=0, slowd_period=16, slowd_matype=0)
|
||||
slowk_52_df, slowd_52_df = talib.STOCH(np_high, np_low, np_close, fastk_period=52, slowk_period=32, slowk_matype=0, slowd_period=32, slowd_matype=0)
|
||||
|
||||
|
||||
# 볼린저 밴드
|
||||
n, t = 10, 2
|
||||
max_10 = close_df.rolling(window=n).mean()
|
||||
stddev_10 = close_df.rolling(window=n).std()
|
||||
upper_10 = max_10 + (stddev_10 * t) # 상단 볼리저 밴드
|
||||
lower_10 = max_10 - (stddev_10 * t) # 하단 볼리저 밴드
|
||||
middle_10 = (upper_10 + lower_10) / 2
|
||||
upper_10 = list(np.reshape(upper_10.values, -1))
|
||||
lower_10 = list(np.reshape(lower_10.values, -1))
|
||||
middle_10 = list(np.reshape(middle_10.values, -1))
|
||||
|
||||
n, t = 20, 2
|
||||
max_20 = close_df.rolling(window=n).mean()
|
||||
stddev_20 = close_df.rolling(window=n).std()
|
||||
upper_20 = max_20 + (stddev_20 * t) # 상단 볼리저 밴드
|
||||
lower_20 = max_20 - (stddev_20 * t) # 하단 볼리저 밴드
|
||||
middle_20 = (upper_20 + lower_20) / 2
|
||||
upper_20 = list(np.reshape(upper_20.values, -1))
|
||||
lower_20 = list(np.reshape(lower_20.values, -1))
|
||||
middle_20 = list(np.reshape(middle_20.values, -1))
|
||||
|
||||
duration = 360
|
||||
laggingSpan_close_diff, laggingSpan_close_diff_rate = self.getDiff_Rate(laggingSpan, close, duration=duration)
|
||||
laggingSpan_avg60_diff, laggingSpan_avg60_diff_rate = self.getDiff_Rate(laggingSpan, avg60, duration=duration)
|
||||
leadingSpan1_leadingSpan2_diff, leadingSpan1_leadingSpan2_diff_rate = self.getDiff_Rate(leadingSpan1, leadingSpan2, duration=duration)
|
||||
|
||||
df_list = [
|
||||
pd.DataFrame(ymd),
|
||||
pd.DataFrame(open), pd.DataFrame(close), pd.DataFrame(high), pd.DataFrame(low), pd.DataFrame(volume),
|
||||
pd.DataFrame(changeLine), pd.DataFrame(baseLine), pd.DataFrame(laggingSpan), pd.DataFrame(leadingSpan1), pd.DataFrame(leadingSpan2),
|
||||
|
||||
pd.DataFrame(laggingSpan_close_diff),
|
||||
pd.DataFrame(laggingSpan_avg60_diff),
|
||||
pd.DataFrame(leadingSpan1_leadingSpan2_diff),
|
||||
|
||||
pd.DataFrame(laggingSpan_close_diff_rate),
|
||||
pd.DataFrame(laggingSpan_avg60_diff_rate),
|
||||
pd.DataFrame(leadingSpan1_leadingSpan2_diff_rate),
|
||||
|
||||
pd.DataFrame(avg5), pd.DataFrame(avg10), pd.DataFrame(avg20), pd.DataFrame(avg60), pd.DataFrame(avg90), pd.DataFrame(avg120), pd.DataFrame(avg240), pd.DataFrame(avg360), pd.DataFrame(avg480),
|
||||
pd.DataFrame(upper_10), pd.DataFrame(lower_10), pd.DataFrame(middle_10),
|
||||
pd.DataFrame(upper_20), pd.DataFrame(lower_20), pd.DataFrame(middle_20),
|
||||
|
||||
pd.DataFrame(new_high_9), pd.DataFrame(new_high_26),
|
||||
pd.DataFrame(new_low_9), pd.DataFrame(new_low_26),
|
||||
pd.DataFrame(slowk_12_df), pd.DataFrame(slowd_12_df),
|
||||
pd.DataFrame(slowk_26_df), pd.DataFrame(slowd_26_df),
|
||||
pd.DataFrame(slowk_52_df), pd.DataFrame(slowd_52_df),
|
||||
|
||||
]
|
||||
|
||||
data = pd.concat(df_list, axis=1)
|
||||
column_names = [
|
||||
'ymd',
|
||||
'open', 'close', 'high', 'low', 'volume',
|
||||
'changeLine', 'baseLine', 'laggingSpan', 'leadingSpan1', 'leadingSpan2',
|
||||
|
||||
'laggingSpan_close_diff',
|
||||
'laggingSpan_avg60_diff',
|
||||
'leadingSpan1_leadingSpan2_diff',
|
||||
|
||||
'laggingSpan_close_diff_rate',
|
||||
'laggingSpan_avg60_diff_rate',
|
||||
'leadingSpan1_leadingSpan2_diff_rate',
|
||||
|
||||
'avg5', 'avg10', 'avg20', 'avg60', 'avg90', 'avg120', 'avg240', 'avg360', 'avg480',
|
||||
|
||||
'upper_10', 'lower_10', 'middle_10',
|
||||
'upper_20', 'lower_20', 'middle_20',
|
||||
|
||||
'new_high_9', 'new_high_26',
|
||||
'new_low_9', 'new_low_26',
|
||||
|
||||
'slowk_12', 'slowd_12',
|
||||
'slowk_26', 'slowd_26',
|
||||
'slowk_52', 'slowd_52',
|
||||
]
|
||||
data.columns = column_names
|
||||
data.index = pd.DatetimeIndex(ymd)
|
||||
|
||||
return data, current_index
|
||||
|
||||
def getData(self, ticker, ymd=None, get_days=14):
|
||||
if ymd is None:
|
||||
result = self.getCoinData(ticker, get_days=get_days)
|
||||
else:
|
||||
result = self.getCoinData(ticker, ymd=ymd, get_days=get_days)
|
||||
|
||||
if len(result['ymd']) < 1:
|
||||
return None, None
|
||||
|
||||
#result_tic = self.makeTickData(result_m1, mins=minute)
|
||||
data, current_index = self.analyze(result)
|
||||
return data, current_index
|
||||
|
||||
if __name__ == "__main__":
|
||||
def min_max_normalize(data):
|
||||
min_val = min(data)
|
||||
max_val = max(data)
|
||||
normalized_data = [(x - min_val) / (max_val - min_val) for x in data]
|
||||
return normalized_data
|
||||
|
||||
|
||||
# 예시 데이터
|
||||
original_data = [-4, -3, -2, -1, 0]
|
||||
normalized_data = min_max_normalize(original_data)
|
||||
print(np.asarray(normalized_data)-1)
|
||||
original_data = [0, 2,4,6,8,10]
|
||||
normalized_data = min_max_normalize(original_data)
|
||||
print(normalized_data)
|
||||
@@ -1,288 +0,0 @@
|
||||
# https://bibot.tistory.com/63
|
||||
# https://nonmeyet.tistory.com/entry/Python-TALib%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-%EB%B9%84%ED%8A%B8%EC%BD%94%EC%9D%B8%EC%A3%BC%EA%B0%80%EA%B8%B0%EC%88%A0%EB%B6%84%EC%84%9D-%EB%B3%B4%EC%A1%B0%EC%A7%80%ED%91%9C-%EC%B6%94%EA%B0%80
|
||||
# https://lunadaddy.tistory.com/122
|
||||
# https://wikidocs.net/186885
|
||||
|
||||
import os
|
||||
from scipy.signal import savgol_filter
|
||||
import numpy as np
|
||||
np.seterr(divide='ignore', invalid='ignore')
|
||||
# https://www.lfd.uci.edu/~gohlke/pythonlibs/#ta-lib
|
||||
# https://lunadaddy.tistory.com/122
|
||||
import talib
|
||||
import pandas as pd
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from stock.analysis.IchimokuCloud import IchimokuCloud
|
||||
from sklearn.preprocessing import StandardScaler
|
||||
from stock.analysis.JSDPattern import JSDPattern
|
||||
|
||||
class JSDPattern_simulation (JSDPattern):
|
||||
|
||||
def __init__(self, RESOURCE_PATH=None):
|
||||
super().__init__(RESOURCE_PATH)
|
||||
return
|
||||
|
||||
def analyze(self, result, mins=1440):
|
||||
result["volume"] = [result["volume"][i] if 0 < result["volume"][i] else 1 for i in range(len(result["volume"]))]
|
||||
# 기본 캔들 정보
|
||||
open_df = pd.DataFrame(result["open"])
|
||||
close_df = pd.DataFrame(result["close"])
|
||||
high_df = pd.DataFrame(result["high"])
|
||||
low_df = pd.DataFrame(result["low"])
|
||||
volume_df = pd.DataFrame(result["volume"])
|
||||
|
||||
# 중복 제거
|
||||
ymd_df = pd.DataFrame(result["ymd"])
|
||||
data_dup = pd.concat([ymd_df, open_df, close_df, high_df, low_df, volume_df], axis=1)
|
||||
data_dup.columns = ["ymd", "open", "close", "high", "low", "volume"]
|
||||
data_dup.index = pd.DatetimeIndex(result["ymd"])
|
||||
data_dup_sorted = data_dup.sort_index(ascending=True)
|
||||
data_dup_sorted = data_dup_sorted.drop_duplicates()
|
||||
|
||||
ymd_df = data_dup_sorted["ymd"]
|
||||
open_df = data_dup_sorted["open"]
|
||||
close_df = data_dup_sorted["close"]
|
||||
high_df = data_dup_sorted["high"]
|
||||
low_df = data_dup_sorted["low"]
|
||||
volume_df = data_dup_sorted["volume"]
|
||||
|
||||
ymd = ymd_df.tolist()
|
||||
open = open_df.tolist()
|
||||
close = close_df.tolist()
|
||||
high = high_df.tolist()
|
||||
low = low_df.tolist()
|
||||
volume = volume_df.tolist()
|
||||
|
||||
# ichimokuCloud
|
||||
df = pd.concat([ymd_df, open_df, close_df, high_df, low_df, volume_df], axis=1)
|
||||
column_names = ['DATE', 'open', 'close', 'high', 'low', 'volume']
|
||||
df.columns = column_names
|
||||
c, b, l, s = 9, 26, 52, 26
|
||||
# 1. 전환선 = (과거 9일 동안 최고가 + 최저가) / 2
|
||||
# 당일을 포함한 9일 동안의 최고가와 최저가의 중간 값을 평균으로 나타낸다.
|
||||
changeLine = (df.high.rolling(c).max() + df.low.rolling(c).min()) / 2
|
||||
# 2. 기준선 = 과거 26일 동안 최고가 + 최저가) / 2
|
||||
# 당일을 포함한 26일 동안의 최고가와 최저가의 중간 값을 평균으로 나타낸다.
|
||||
baseLine = (df.high.rolling(b).max() + df.low.rolling(b).min()) / 2
|
||||
|
||||
# 3. 후행스팬 = 현재 close가격의 26일전 반영
|
||||
laggingSpan = [df.close.values[i + s] for i in range(len(df.close) - s)]
|
||||
laggingSpan += [None for i in range(s)]
|
||||
laggingSpan = np.array(laggingSpan)
|
||||
|
||||
# 4. 선행스팬 1 = ((기준선 + 전환선) / 2)를 26일 선행하여 배치
|
||||
# 전환선과 기준선의 평균값을 구해 당일 포함 26일 앞으로 이동시킨 선 (중-단기 구간의 힘을 보여줌)
|
||||
tmp_leadingSpan1 = (changeLine + baseLine) / 2
|
||||
""" S: 26일 선행시킴 """
|
||||
leadingSpan1 = list(tmp_leadingSpan1.values)
|
||||
for i in range(b - 1):
|
||||
leadingSpan1.insert(0, None)
|
||||
""" E: 26일 선행시킴 """
|
||||
|
||||
# 5. 선행스팬 2 = ((최근 52일 동안 최고가 + 최저가) / 2)를 26일 선행하여 배치
|
||||
# 당일을 포함한 52일 동안의 최고가와 최저가의 평균을 26일 앞으로 이동시킨 선 (장기으로 형성된 선이기 때문에 가장 느리게 변함)
|
||||
tmp_leadingSpan2 = (df.high.rolling(l).max() + df.low.rolling(l).min()) / 2
|
||||
""" S: 52일 선행시킴 """
|
||||
leadingSpan2 = list(tmp_leadingSpan2.values)
|
||||
for i in range(l - 1):
|
||||
leadingSpan2.insert(0, None)
|
||||
""" S: 52일 선행시킴 """
|
||||
|
||||
baseLine = baseLine.tolist()
|
||||
changeLine = changeLine.tolist()
|
||||
laggingSpan = list(laggingSpan)
|
||||
current_index = len(ymd)
|
||||
for i in range(51):
|
||||
if len(ymd) < len(leadingSpan2):
|
||||
if mins==1440:
|
||||
ymd.append(ymd[-1] + timedelta(days=1))
|
||||
else:
|
||||
ymd.append(ymd[-1] + timedelta(minutes=1))
|
||||
if len(open) < len(leadingSpan2):
|
||||
open.append(None)
|
||||
if len(close) < len(leadingSpan2):
|
||||
close.append(None)
|
||||
if len(high) < len(leadingSpan2):
|
||||
high.append(None)
|
||||
if len(low) < len(leadingSpan2):
|
||||
low.append(None)
|
||||
if len(volume) < len(leadingSpan2):
|
||||
volume.append(None)
|
||||
if len(baseLine) < len(leadingSpan2):
|
||||
baseLine.append(None)
|
||||
if len(changeLine) < len(leadingSpan2):
|
||||
changeLine.append(None)
|
||||
if len(laggingSpan) < len(leadingSpan2):
|
||||
laggingSpan.append(None)
|
||||
for i in range(26):
|
||||
if len(leadingSpan1) < len(leadingSpan2):
|
||||
leadingSpan1.append(leadingSpan1[-1])
|
||||
|
||||
# 9일 신고가
|
||||
new_high_9 = [0 for c in range(8)] + [1 if (changeLine[c-1] is not None and changeLine[c] is not None and changeLine[c-1] < changeLine[c]) and None not in close[c-8:c+1] and max(close[c-8:c]) < close[c] else 0 for c in range(8, len(close))]
|
||||
# 26일 신고가
|
||||
new_high_26 = [0 for c in range(25)] + [1 if (baseLine[c-1] is not None and baseLine[c] is not None and baseLine[c-1] < baseLine[c]) and None not in close[c-8:c+1] and max(close[c-25:c]) < close[c] else 0 for c in range(25, len(close))]
|
||||
|
||||
# 9일 신저가
|
||||
new_low_9 = [0 for c in range(8)] + [1 if (changeLine[c-1] is not None and changeLine[c] is not None and changeLine[c-1] < changeLine[c]) and None not in close[c-8:c+1] and close[c-9] < min(close[c-8:c+1]) else 0 for c in range(8, len(close))]
|
||||
# 26일 신저가
|
||||
new_low_26 = [0 for c in range(25)] + [1 if (baseLine[c-1] is not None and baseLine[c] is not None and baseLine[c-1] < baseLine[c]) and None not in close[c-8:c+1] and close[c-26] < min(close[c-25:c+1]) else 0 for c in range(25, len(close))]
|
||||
|
||||
|
||||
# 이동 평균
|
||||
close_df = pd.DataFrame(close)
|
||||
avg5 = list(np.reshape(close_df.ewm(5).mean().values, -1))
|
||||
avg10 = list(np.reshape(close_df.ewm(10).mean().values, -1))
|
||||
avg20 = list(np.reshape(close_df.ewm(20).mean().values, -1))
|
||||
avg60 = list(np.reshape(close_df.ewm(60).mean().values, -1))
|
||||
avg90 = list(np.reshape(close_df.ewm(90).mean().values, -1))
|
||||
avg120 = list(np.reshape(close_df.ewm(120).mean().values, -1))
|
||||
avg240 = list(np.reshape(close_df.ewm(240).mean().values, -1))
|
||||
avg360 = list(np.reshape(close_df.ewm(360).mean().values, -1))
|
||||
avg480 = list(np.reshape(close_df.ewm(480).mean().values, -1))
|
||||
avg720 = list(np.reshape(close_df.ewm(720).mean().values, -1))
|
||||
avg1440 = list(np.reshape(close_df.ewm(1440).mean().values, -1))
|
||||
avg2880 = list(np.reshape(close_df.ewm(2880).mean().values, -1))
|
||||
|
||||
np_high, np_low, np_close = np.array(high, dtype=np.float64), np.array(low, dtype=np.float64), np.array(close, dtype=np.float64)
|
||||
slowk_12_df, slowd_12_df = talib.STOCH(np_high, np_low, np_close, fastk_period=12, slowk_period=5, slowk_matype=0, slowd_period=5, slowd_matype=0)
|
||||
slowk_26_df, slowd_26_df = talib.STOCH(np_high, np_low, np_close, fastk_period=26, slowk_period=16, slowk_matype=0, slowd_period=16, slowd_matype=0)
|
||||
slowk_52_df, slowd_52_df = talib.STOCH(np_high, np_low, np_close, fastk_period=52, slowk_period=32, slowk_matype=0, slowd_period=32, slowd_matype=0)
|
||||
|
||||
|
||||
# 최고/최저 위치
|
||||
loc_240 = [None for i in range(len(close))]
|
||||
for i in range(240, len(close)):
|
||||
min_v = np.min(result["close"][i-239:i+1])
|
||||
max_v = np.max(result["close"][i-239:i+1])
|
||||
if close[i] is not None:
|
||||
loc_240[i] = ((close[i] - min_v) / (max_v - min_v))
|
||||
else:
|
||||
loc_240[i] = None
|
||||
|
||||
loc_240 = pd.DataFrame(loc_240)
|
||||
loc_240_k = loc_240.to_numpy().reshape(-1)
|
||||
loc_240_d = loc_240.rolling(20).mean()
|
||||
loc_240_s = loc_240.rolling(60).mean()
|
||||
loc_240_d = loc_240_d.to_numpy().reshape(-1)
|
||||
loc_240_s = loc_240_s.to_numpy().reshape(-1)
|
||||
|
||||
# 볼린저 밴드
|
||||
n, t = 10, 2
|
||||
max_10 = close_df.rolling(window=n).mean()
|
||||
stddev_10 = close_df.rolling(window=n).std()
|
||||
upper_10 = max_10 + (stddev_10 * t) # 상단 볼리저 밴드
|
||||
lower_10 = max_10 - (stddev_10 * t) # 하단 볼리저 밴드
|
||||
middle_10 = (upper_10 + lower_10) / 2
|
||||
upper_10 = list(np.reshape(upper_10.values, -1))
|
||||
lower_10 = list(np.reshape(lower_10.values, -1))
|
||||
middle_10 = list(np.reshape(middle_10.values, -1))
|
||||
|
||||
n, t = 20, 2
|
||||
max_20 = close_df.rolling(window=n).mean()
|
||||
stddev_20 = close_df.rolling(window=n).std()
|
||||
upper_20 = max_20 + (stddev_20 * t) # 상단 볼리저 밴드
|
||||
lower_20 = max_20 - (stddev_20 * t) # 하단 볼리저 밴드
|
||||
middle_20 = (upper_20 + lower_20) / 2
|
||||
upper_20 = list(np.reshape(upper_20.values, -1))
|
||||
lower_20 = list(np.reshape(lower_20.values, -1))
|
||||
middle_20 = list(np.reshape(middle_20.values, -1))
|
||||
|
||||
duration = 1440
|
||||
if mins == 1440:
|
||||
duration = 360
|
||||
laggingSpan_close_diff, laggingSpan_close_diff_rate = self.getDiff_Rate(laggingSpan, close, duration=duration)
|
||||
laggingSpan_avg60_diff, laggingSpan_avg60_diff_rate = self.getDiff_Rate(laggingSpan, avg60, duration=duration)
|
||||
leadingSpan1_leadingSpan2_diff, leadingSpan1_leadingSpan2_diff_rate = self.getDiff_Rate(leadingSpan1, leadingSpan2, duration=duration)
|
||||
|
||||
|
||||
df_list = [
|
||||
pd.DataFrame(ymd),
|
||||
pd.DataFrame(open), pd.DataFrame(close), pd.DataFrame(high), pd.DataFrame(low), pd.DataFrame(volume),
|
||||
pd.DataFrame(changeLine), pd.DataFrame(baseLine), pd.DataFrame(laggingSpan), pd.DataFrame(leadingSpan1), pd.DataFrame(leadingSpan2),
|
||||
|
||||
pd.DataFrame(laggingSpan_close_diff),
|
||||
pd.DataFrame(laggingSpan_avg60_diff),
|
||||
pd.DataFrame(leadingSpan1_leadingSpan2_diff),
|
||||
|
||||
pd.DataFrame(laggingSpan_close_diff_rate),
|
||||
pd.DataFrame(laggingSpan_avg60_diff_rate),
|
||||
pd.DataFrame(leadingSpan1_leadingSpan2_diff_rate),
|
||||
|
||||
pd.DataFrame(loc_240_k), pd.DataFrame(loc_240_d), pd.DataFrame(loc_240_s),
|
||||
|
||||
pd.DataFrame(avg5), pd.DataFrame(avg10), pd.DataFrame(avg20), pd.DataFrame(avg60), pd.DataFrame(avg90), pd.DataFrame(avg120), pd.DataFrame(avg240), pd.DataFrame(avg360), pd.DataFrame(avg480), pd.DataFrame(avg720), pd.DataFrame(avg1440), pd.DataFrame(avg2880),
|
||||
pd.DataFrame(upper_10), pd.DataFrame(lower_10), pd.DataFrame(middle_10),
|
||||
pd.DataFrame(upper_20), pd.DataFrame(lower_20), pd.DataFrame(middle_20),
|
||||
|
||||
pd.DataFrame(new_high_9), pd.DataFrame(new_high_26),
|
||||
pd.DataFrame(new_low_9), pd.DataFrame(new_low_26),
|
||||
pd.DataFrame(slowk_12_df), pd.DataFrame(slowd_12_df),
|
||||
pd.DataFrame(slowk_26_df), pd.DataFrame(slowd_26_df),
|
||||
pd.DataFrame(slowk_52_df), pd.DataFrame(slowd_52_df),
|
||||
|
||||
]
|
||||
|
||||
data = pd.concat(df_list, axis=1)
|
||||
column_names = [
|
||||
'ymd',
|
||||
'open', 'close', 'high', 'low', 'volume',
|
||||
'changeLine', 'baseLine', 'laggingSpan', 'leadingSpan1', 'leadingSpan2',
|
||||
|
||||
'laggingSpan_close_diff',
|
||||
'laggingSpan_avg60_diff',
|
||||
'leadingSpan1_leadingSpan2_diff',
|
||||
|
||||
'laggingSpan_close_diff_rate',
|
||||
'laggingSpan_avg60_diff_rate',
|
||||
'leadingSpan1_leadingSpan2_diff_rate',
|
||||
|
||||
'loc_240_k', 'loc_240_d', 'loc_240_s',
|
||||
|
||||
'avg5', 'avg10', 'avg20', 'avg60', 'avg90', 'avg120', 'avg240', 'avg360', 'avg480', 'avg720', 'avg1440', 'avg2880',
|
||||
|
||||
'upper_10', 'lower_10', 'middle_10',
|
||||
'upper_20', 'lower_20', 'middle_20',
|
||||
|
||||
'new_high_9', 'new_high_26',
|
||||
'new_low_9', 'new_low_26',
|
||||
|
||||
'slowk_12', 'slowd_12',
|
||||
'slowk_26', 'slowd_26',
|
||||
'slowk_52', 'slowd_52',
|
||||
]
|
||||
data.columns = column_names
|
||||
data.index = pd.DatetimeIndex(ymd)
|
||||
|
||||
return data, current_index
|
||||
|
||||
def getData(self, ticker, ymd=None, get_days=14):
|
||||
if ymd is None:
|
||||
result = self.getCoinData(ticker, get_days=get_days)
|
||||
else:
|
||||
result = self.getCoinData(ticker, ymd=ymd, get_days=get_days)
|
||||
|
||||
if len(result['ymd']) < 1:
|
||||
return None, None
|
||||
|
||||
#result_tic = self.makeTickData(result_m1, mins=minute)
|
||||
data, current_index = self.analyze(result)
|
||||
return data, current_index
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
def min_max_normalize(data):
|
||||
min_val = min(data)
|
||||
max_val = max(data)
|
||||
normalized_data = [(x - min_val) / (max_val - min_val) for x in data]
|
||||
return normalized_data
|
||||
|
||||
|
||||
# 예시 데이터
|
||||
original_data = [-4, -3, -2, -1, 0]
|
||||
normalized_data = min_max_normalize(original_data)
|
||||
print(np.asarray(normalized_data)-1)
|
||||
original_data = [0, 2,4,6,8,10]
|
||||
normalized_data = min_max_normalize(original_data)
|
||||
print(normalized_data)
|
||||
@@ -121,7 +121,7 @@ class FnGuideCrawler:
|
||||
item_code = item[1]
|
||||
|
||||
idx += 1
|
||||
print(idx, item_code, item_name, 'http://comp.fnguide.com/SVO2/ASP/SVD_main.asp?pGB=1&gicode=A%s'%(item_code.strip()))
|
||||
print("{}. {} ({}) {}".format(idx, item_code, item_name, 'http://comp.fnguide.com/SVO2/ASP/SVD_main.asp?pGB=1&gicode=A%s'%(item_code.strip())))
|
||||
|
||||
fnGuideData = self.get_fnguide_table(item_code)
|
||||
|
||||
|
||||
@@ -46,8 +46,8 @@ class MetaCrawler:
|
||||
inputs.append({'NAME': 'RUB', 'CODE': 'FX_RUBKRW', 'URL': 'http://finance.naver.com/marketindex/exchangeDailyQuote.nhn?marketindexCd=FX_RUBKRW'}) # 러시아 RUB
|
||||
inputs.append({'NAME': 'TWD', 'CODE': 'FX_TWDKRW', 'URL': 'http://finance.naver.com/marketindex/exchangeDailyQuote.nhn?marketindexCd=FX_TWDKRW'}) # 대만 TWD
|
||||
|
||||
for i in range(len(inputs)):
|
||||
input = inputs[i]
|
||||
for idx in range(len(inputs)):
|
||||
input = inputs[idx]
|
||||
NAME = input['NAME']
|
||||
CODE = input['CODE']
|
||||
|
||||
@@ -100,7 +100,7 @@ class MetaCrawler:
|
||||
finish = True
|
||||
break
|
||||
|
||||
print(CODE, NAME, ymd)
|
||||
print("{}. {} {} ({})".format(idx, ymd, CODE, NAME))
|
||||
if finish:
|
||||
break
|
||||
|
||||
@@ -191,7 +191,7 @@ class MetaCrawler:
|
||||
finish = True
|
||||
break
|
||||
|
||||
print ("20"+item[0])
|
||||
print ("Trading_Trend 20{}".format(item[0]))
|
||||
previousDay = html[0].values[2][0]
|
||||
if finish:
|
||||
break
|
||||
@@ -271,7 +271,7 @@ class MetaCrawler:
|
||||
finish = True
|
||||
break
|
||||
|
||||
print("20"+item[0])
|
||||
print("crawl_money_trend 20{}".format(item[0]))
|
||||
if finish:
|
||||
break
|
||||
previousDay = html[0].values[2][0]
|
||||
@@ -301,8 +301,8 @@ class MetaCrawler:
|
||||
inputs.append({'NAME': '국고채(3년)', 'CODE': 'IRR_GOVT03Y', 'URL': 'http://finance.naver.com/marketindex/interestDailyQuote.nhn?marketindexCd=IRR_GOVT03Y'})
|
||||
inputs.append({'NAME': '회사채(3년)', 'CODE': 'IRR_CORP03Y', 'URL': 'http://finance.naver.com/marketindex/interestDailyQuote.nhn?marketindexCd=IRR_CORP03Y'})
|
||||
|
||||
for i in range(len(inputs)):
|
||||
input = inputs[i]
|
||||
for idx in range(len(inputs)):
|
||||
input = inputs[idx]
|
||||
NAME = input['NAME']
|
||||
CODE = input['CODE']
|
||||
|
||||
@@ -357,7 +357,7 @@ class MetaCrawler:
|
||||
|
||||
if finish:
|
||||
break
|
||||
print(NAME + " / " + ymd)
|
||||
print("{} {}".format(ymd, NAME))
|
||||
|
||||
conn.commit()
|
||||
cursor.close()
|
||||
@@ -393,8 +393,8 @@ class MetaCrawler:
|
||||
inputs.append({'NAME': 'PLATINUM', 'CODE': 'CMDT_PL','URL': 'http://finance.naver.com/marketindex/worldDailyQuote.nhn?marketindexCd=CMDT_PL&fdtc=2'}) # 국제 백금
|
||||
inputs.append({'NAME': 'PALADIUM', 'CODE': 'CMDT_PA','URL': 'http://finance.naver.com/marketindex/worldDailyQuote.nhn?marketindexCd=CMDT_PA&fdtc=2'}) # 국제 팔라듐
|
||||
|
||||
for i in range(len(inputs)):
|
||||
input = inputs[i]
|
||||
for idx in range(len(inputs)):
|
||||
input = inputs[idx]
|
||||
NAME = input['NAME']
|
||||
CODE = input['CODE']
|
||||
|
||||
@@ -444,7 +444,7 @@ class MetaCrawler:
|
||||
finish = True
|
||||
break
|
||||
|
||||
print(CODE, NAME, ymd)
|
||||
print("{}. {} {} ({})".format(idx, ymd, CODE, NAME))
|
||||
if finish:
|
||||
break
|
||||
|
||||
|
||||
@@ -132,10 +132,7 @@ class StockCrawler:
|
||||
stocks.append({"NAME": 'KODEX 은행', "CODE": "091170"})
|
||||
stocks.append({"NAME": 'TIGER 탄소효율그린뉴딜', "CODE": "376410"})
|
||||
|
||||
start_time = time.time()
|
||||
for i, stock in enumerate(stocks):
|
||||
print (i, stock["NAME"], stock["CODE"], (time.time()-start_time), "s")
|
||||
start_time = time.time()
|
||||
cursor.execute('SELECT ymd FROM ' + tableName + ' WHERE CODE=? order by ymd desc', (stock["CODE"],))
|
||||
result = cursor.fetchone()
|
||||
ymd = self.START_DATE
|
||||
@@ -153,6 +150,7 @@ class StockCrawler:
|
||||
#else:
|
||||
# cursor.execute("UPDATE " + tableName + " SET close=?, diff=?, open=?, high=?, low=?, volume=? WHERE CODE=? and ymd=?", (item['close'], item['diff'], item['open'], item['high'], item['low'], item['volume'], stock["CODE"], item['ymd']))
|
||||
|
||||
print("{}. {} ({})".format(i, stock["CODE"], stock["NAME"]))
|
||||
sleep(0.5)
|
||||
conn.commit()
|
||||
cursor.close()
|
||||
@@ -178,7 +176,6 @@ class StockCrawler:
|
||||
code_df = self.getStockInfo()
|
||||
items = code_df.values
|
||||
|
||||
start_time = time.time()
|
||||
idx = 0
|
||||
for item in items:
|
||||
idx += 1
|
||||
@@ -211,9 +208,7 @@ class StockCrawler:
|
||||
conn.commit()
|
||||
cursor.close()
|
||||
conn.close()
|
||||
print(idx, item_name, item_code, (time.time() - start_time), "s")
|
||||
|
||||
start_time = time.time()
|
||||
print("{}. {} ({})".format(idx, item_code, item_name))
|
||||
sleep(0.3)
|
||||
|
||||
return
|
||||
@@ -234,8 +229,6 @@ class StockCrawler:
|
||||
cursor.close()
|
||||
conn.close()
|
||||
|
||||
start_time = time.time()
|
||||
|
||||
pd.options.display.float_format = '{:.4f}'.format
|
||||
pd.set_option('display.max_columns', None)
|
||||
|
||||
@@ -372,9 +365,8 @@ class StockCrawler:
|
||||
conn.commit()
|
||||
cursor.close()
|
||||
conn.close()
|
||||
print(idx, item_code, special_stocks[item_code], (time.time() - start_time), "s")
|
||||
|
||||
start_time = time.time()
|
||||
print("{}. {} ({})".format(idx, item_code, special_stocks[item_code]))
|
||||
sleep(0.05)
|
||||
return
|
||||
|
||||
|
||||
Reference in New Issue
Block a user