import os
import time
import shutil
import matplotlib.pyplot as plt
import datetime
import sqlite3
from datetime import datetime
from matplotlib import rc
import pandas as pd
import copy

rc('font', family='AppleGothic')
plt.rcParams['axes.unicode_minus'] = False

import plotly.graph_objs as go
from plotly import tools, subplots
import plotly.io as po

from stock.analysis.Common import Common
from stock.analysis.Stochastic import Stochastic
from stock.analysis.BolingerBand import BolingerBand
from stock.analysis.IchimokuCloud import IchimokuCloud
from stock.analysis.RSI import RSI
from stock.crawler.MovingAverage import MovingAverage

class AnalyzerSqlite:
    PROJECT_HOME = None

    stochastic = None
    bolingerBand = None
    ichimokuCloud = None
    rsi = None

    topCompany = None
    fnguide = None

    common = None
    stockFileName = None
    analyzedFileName = None

    moving_avg = None

    def __init__(self, PROJECT_HOME, stockFileName):
        self.PROJECT_HOME = PROJECT_HOME
        self.stockFileName = stockFileName

        self.common = Common()

        self.stochastic = Stochastic()
        self.bolingerBand = BolingerBand()
        self.ichimokuCloud = IchimokuCloud()
        self.rsi = RSI()

        self.topCompany = self.getTopCompany(stockFileName, 2000)
        self.fnguide = self.readFnguide(stockFileName)

        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 draw(self, stock):

        ymd = list(reversed(stock['ymd']))
        open = list(reversed(stock['open']))
        close = list(reversed(stock['close']))
        high = list(reversed(stock['high']))
        low = list(reversed(stock['low']))
        volume = list(reversed(stock['volume']))
        avg3 = list(reversed(stock['avg3']))
        avg4 = list(reversed(stock['avg4']))
        avg5 = list(reversed(stock['avg5']))
        avg6 = list(reversed(stock['avg6']))
        avg10 = list(reversed(stock['avg10']))
        avg12 = list(reversed(stock['avg12']))
        avg20 = list(reversed(stock['avg20']))
        avg36 = list(reversed(stock['avg36']))
        avg40 = list(reversed(stock['avg40']))
        avg48 = list(reversed(stock['avg48']))
        avg60 = list(reversed(stock['avg60']))
        avg120 = list(reversed(stock['avg120']))
        avg240 = list(reversed(stock['avg240']))
        avg300 = list(reversed(stock['avg300']))
        rsi = list(reversed(stock['rsi']))
        rsis = list(reversed(stock['rsis']))
        stochastic_slow_k = list(reversed(stock['stochastic_slow_k']))
        stochastic_slow_d = list(reversed(stock['stochastic_slow_d']))
        bolingerband_upper = list(reversed(stock['bolingerband_upper']))
        bolingerband_lower = list(reversed(stock['bolingerband_lower']))
        ichimokucloud_changeLine = list(reversed(stock['ichimokucloud_changeLine']))
        ichimokucloud_baseLine = list(reversed(stock['ichimokucloud_baseLine']))

        # general
        candle_stick = go.Candlestick(x=ymd, open=open, high=high, low=low, close=close, increasing_line_color='red', decreasing_line_color='blue')
        avg3 = go.Scatter(x=ymd, y=avg3, name="avg3", line_color='#085F1B')
        avg4 = go.Scatter(x=ymd, y=avg4, name="avg4", line_color='#085F1B')
        avg5 = go.Scatter(x=ymd, y=avg5, name="avg5", line_color='#000000')
        avg6 = go.Scatter(x=ymd, y=avg6, name="avg6", line_color='#698D09')
        avg10 = go.Scatter(x=ymd, y=avg10, name="avg10", line_color='#041366')
        avg12 = go.Scatter(x=ymd, y=avg12, name="avg12", line_color='#6C2507')
        avg20 = go.Scatter(x=ymd, y=avg20, name="avg20", line_color='#f84c43')
        avg36 = go.Scatter(x=ymd, y=avg36, name="avg36", line_color='#370557')
        avg40 = go.Scatter(x=ymd, y=avg40, name="avg40", line_color='#8013ED')
        avg48 = go.Scatter(x=ymd, y=avg48, name="avg48", line_color='#7A1E66')
        avg60 = go.Scatter(x=ymd, y=avg60, name="avg60", line_color='#f89543')
        avg120 = go.Scatter(x=ymd, y=avg120, name="avg120", line_color='#0ed604')
        avg240 = go.Scatter(x=ymd, y=avg240, name="avg240", line_color='#FF00F7')
        avg300 = go.Scatter(x=ymd, y=avg300, name="avg300", line_color='#00FF49')
        bolinger_upper = go.Scatter(x=ymd, y=bolingerband_upper, name="upper", line_color='#8B4513')
        bolinger_lower = go.Scatter(x=ymd, y=bolingerband_lower, name="lower", line_color='#8B4513')
        changeLine = go.Scatter(x=ymd, y=ichimokucloud_changeLine, name="changeLine", line_color='#000000')
        baseLine = go.Scatter(x=ymd, y=ichimokucloud_baseLine, name="baseLine", line_color='#FF0000')

        candle_data = [candle_stick, avg3, avg4, avg5, avg6, avg10, avg12, avg20, avg36, avg40, avg48, avg60, avg120, avg240, avg300, bolinger_upper, bolinger_lower, changeLine, baseLine]
        #candle_data = [candle_stick, bolinger_upper, bolinger_lower, changeLine, baseLine]

        volume = go.Bar(x=ymd, y=volume, name="volume")
        volume_data = [volume]

        # stochastic
        rsi = go.Scatter(x=ymd, y=rsi, name="rsi", line_color='#8B4513')
        rsis = go.Scatter(x=ymd, y=rsis, name="rsis", line_color='#4169E1')
        rsi_data = [rsi, rsis]

        # stochastic
        slow_k = go.Scatter(x=ymd, y=stochastic_slow_k, name="Slow%K", line_color='#8B4513')
        slow_d = go.Scatter(x=ymd, y=stochastic_slow_d, name="Slow%D", line_color='#4169E1')
        stochastic_data = [slow_k, slow_d]

        fig = subplots.make_subplots(rows=4, cols=1,
                                     subplot_titles=('차트', '거래량', 'rsi', 'Stochastic'),
                                     row_heights=[1200, 500, 500, 500])

        for trace in candle_data:
            fig.append_trace(trace, 1, 1)
        for trace in volume_data:
            fig.append_trace(trace, 2, 1)
        for trace in rsi_data:
            fig.append_trace(trace, 3, 1)
        for trace in stochastic_data:
            fig.append_trace(trace, 4, 1)

        fig.update_layout(height=2200, xaxis_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 makeDir(self, type):
        if os.path.isdir(self.outPath + "/" + type):
            os.rmdir(self.outPath + "/" + type)
        os.mkdir(self.outPath + "/" + type)
        return

    def makeDirectory(self, outPath):
        self.outPath = outPath
        if os.path.isdir(outPath):
            shutil.rmtree(outPath)
        os.mkdir(outPath)
        self.makeDir("final")

        self.makeDir("daily_3일선_10일선_상향돌파")
        self.makeDir("daily_3일선_10일선_하향돌파")

        self.makeDir("weekly_4주선_48주선_상향돌파")
        self.makeDir("weekly_종가_12주선_상향돌파")
        self.makeDir("weekly_rsi_20이하")
        self.makeDir("weekly_rsi_rsis_위로_올라옴")
        self.makeDir("weekly_BB하단_내려옴")

        self.makeDir("monthly_6월선_36월선_상향돌파")
        self.makeDir("monthly_종가_12월선_상향돌파")
        self.makeDir("monthly_rsi_30이하")
        self.makeDir("monthly_rsi_rsis_위로_올라옴")
        self.makeDir("monthly_BB하단_내려옴")

        self.makeDir("daily_rsi_10이하")
        self.makeDir("daily_이전에_없던_거래량")
        self.makeDir("daily_BB하단_내려옴")
        self.makeDir("daily_종가_60일선_상향돌파")

        return

    def writeFile(self, type, CODE, NAME, top, stock, state, final_status_count=-1):
        # 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(stock)
            title = "%s (%s), %d, %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>)" % (NAME, CODE, stock['close'][0], type, CODE, CODE)
            fig['layout'].update(title=title)

            fileName = self.outPath + "/" + str(type)
            if final_status_count == -1:
                fileName = "%s/%s_%s_%s_%s.html" % (fileName, top, NAME.replace(" ", ""), CODE, state)
            else:
                fileName = "%s/%s_%s_%s_%s_%s.html" % (fileName, str(final_status_count), top, NAME.replace(" ", ""), CODE, state)
            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, TableName, CODE):
        conn = sqlite3.connect(self.stockFileName)
        cursor = conn.cursor()

        sql = 'SELECT ymd, close, open, high, low, volume, '
        sql += ' avg3, avg4, avg5, avg6, avg10, avg12, avg20, avg36, avg40, avg48, avg60, avg120, avg200, avg240, avg300, '
        sql += ' bolingerband_upper, bolingerband_lower, bolingerband_middle, '
        sql += ' ichimokucloud_changeLine, ichimokucloud_baseLine, ichimokucloud_leadingSpan1, ichimokucloud_leadingSpan2, '
        sql += ' stochastic_fast_k, stochastic_slow_k, stochastic_slow_d, '
        sql += ' rsi, rsis '
        sql += ' FROM ' + TableName + ' where CODE=? order by ymd desc limit 512'
        cursor.execute(sql, (CODE,))
        prices = cursor.fetchall()

        cursor.close()
        conn.close()

        ymd = []
        close, open, high, low, volume = [], [], [], [], []
        avg3, avg4, avg5, avg6, avg10, avg12, avg20, avg36, avg40, avg48, avg60, avg120, avg200, avg240, avg300 = [], [], [], [], [], [], [], [], [], [], [], [], [], [], []
        bolingerband_upper, bolingerband_lower, bolingerband_middle = [], [], []
        ichimokucloud_changeLine, ichimokucloud_baseLine, ichimokucloud_leadingSpan1, ichimokucloud_leadingSpan2 = [], [], [], []
        stochastic_fast_k, stochastic_slow_k, stochastic_slow_d = [], [], []
        rsi, rsis = [], []

        for price in prices:
            ymd.append(price[0])
            close.append(price[1])
            open.append(price[2])
            high.append(price[3])
            low.append(price[4])
            volume.append(price[5])
            avg3.append(price[6])
            avg4.append(price[7])
            avg5.append(price[8])
            avg6.append(price[9])
            avg10.append(price[10])
            avg12.append(price[11])
            avg20.append(price[12])
            avg36.append(price[13])
            avg40.append(price[14])
            avg48.append(price[15])
            avg60.append(price[16])
            avg120.append(price[17])
            avg200.append(price[18])
            avg240.append(price[19])
            avg300.append(price[20])
            bolingerband_upper.append(price[21])
            bolingerband_lower.append(price[22])
            bolingerband_middle.append(price[23])
            ichimokucloud_changeLine.append(price[24])
            ichimokucloud_baseLine.append(price[25])
            ichimokucloud_leadingSpan1.append(price[26])
            ichimokucloud_leadingSpan2.append(price[27])
            stochastic_fast_k.append(price[28])
            stochastic_slow_k.append(price[29])
            stochastic_slow_d.append(price[30])
            rsi.append(price[31])
            rsis.append(price[32])

        stock = {
            "ymd": ymd,
            "close": close, "open": open, "high": high, "low": low, "volume": volume,
            "avg3": avg3, "avg4": avg4, "avg5": avg5, "avg6": avg6, "avg10": avg10, "avg12": avg12, "avg20": avg20, "avg36": avg36, "avg40": avg40, "avg48": avg48, "avg60": avg60, "avg120": avg120, "avg200": avg200, "avg300": avg300,
            "avg240": avg240,
            "bolingerband_upper": bolingerband_upper, "bolingerband_lower": bolingerband_lower,
            "bolingerband_middle": bolingerband_middle,
            "ichimokucloud_changeLine": ichimokucloud_changeLine, "ichimokucloud_baseLine": ichimokucloud_baseLine,
            "ichimokucloud_leadingSpan1": ichimokucloud_leadingSpan1,
            "ichimokucloud_leadingSpan2": ichimokucloud_leadingSpan2,
            "stochastic_fast_k": stochastic_fast_k, "stochastic_slow_k": stochastic_slow_k, "stochastic_slow_d": stochastic_slow_d,
            "rsi": rsi, "rsis": rsis
        }

        return stock

    # 후보 찾기
    def findCandidate(self, outPath):
        self.makeDirectory(outPath)

        stockTableName = 'stock'
        stockAnalysisTableName = 'stock_analysis'
        stockAnalysisWeeklyTableName = 'stock_analysis_weekly'
        stockAnalysisMonthlyTableName = 'stock_analysis_monthly'

        conn = sqlite3.connect(self.stockFileName)
        cursor = conn.cursor()

        cursor.execute('SELECT distinct code, name FROM ' + stockTableName + ' order by code')
        items = cursor.fetchall()

        cursor.close()
        conn.close()

        for idx, item in enumerate(items):
            CODE = item[0]
            NAME = item[1]
            print (idx, CODE, NAME)
            print("Analysis # :", idx, ", CODE: ", CODE, ", NAME: ", NAME)

            top = "0"
            if CODE in self.topCompany:
                top = str(self.topCompany[CODE][0])

            stock_daily = self.getStockData(stockAnalysisTableName, CODE)
            stock_weekly = self.getStockData(stockAnalysisWeeklyTableName, CODE)
            stock_monthly = self.getStockData(stockAnalysisMonthlyTableName, CODE)

            status = ""
            final_status = ""
            final_status_count = 0

            # 거래량이 100만 이상이고, 종가가 1천원 이상인지 체크 (https://happpy-rich.tistory.com/94)
            if stock_weekly['volume'][0] > 100000 and stock_weekly['close'][0] > 1000:

                # 종목 상태 체크 분석

                # [Weekly]
                # 정배열 체크
                temp_status = self.common.check_RightArrange(stock_weekly)
                if temp_status != "":
                    status += temp_status

                # 4주선이 48주 선을 상향 돌파함
                if len(stock_weekly['close']) > 40:
                    if (stock_weekly['avg4'][1] is not None and stock_weekly['avg48'][1] is not None and
                        stock_weekly['avg4'][0] is not None and stock_weekly['avg48'][0] is not None):
                        if stock_weekly['avg4'][1] <= stock_weekly['avg48'][1] and stock_weekly['avg4'][0] > stock_weekly['avg48'][0]:
                            type = "weekly_4주선_48주선_상향돌파"
                            final_status += " " + type
                            final_status_count += 1
                            self.writeFile(type, CODE, NAME, top, stock_weekly, status)

                # 종가가 20주선을 상향 돌파함
                if len(stock_weekly['close']) > 2:
                    if stock_weekly['close'][1] is not None and stock_weekly['avg12'][1] is not None and stock_weekly['close'][0] is not None and stock_weekly['avg12'][0] is not None:
                        if stock_weekly['close'][1] <= stock_weekly['avg12'][1] and stock_weekly['close'][0] > stock_weekly['avg12'][0]:
                            type = "weekly_종가_12주선_상향돌파"
                            final_status += " " + type
                            final_status_count += 1
                            self.writeFile(type, CODE, NAME, top, stock_weekly, status)

                # RSI가 32 이하인 경우 (30이 이하로 떨어지는 것 미리 확인)
                if len(stock_monthly['close']) > 1:
                    if stock_weekly['rsi'][0] is not None:
                        if stock_weekly['rsi'][0] <= 20:
                            type = "weekly_rsi_20이하"
                            final_status += " " + type
                            final_status_count += 1
                            self.writeFile(type, CODE, NAME, top, stock_weekly, status)

                # rsi가 40 이하이고, rsis 아래에서 위로 올라올 때
                if len(stock_weekly['close']) > 60:
                    if stock_weekly['rsi'][0] is not None and stock_weekly['rsis'][0] is not None and stock_weekly['rsi'][1] is not None and stock_weekly['rsis'][1] is not None:
                        if stock_weekly['rsi'][0] < 40:
                            if stock_weekly['rsi'][0] > stock_weekly['rsis'][0] and stock_weekly['rsi'][1] <= stock_weekly['rsis'][1]:
                                type = "weekly_rsi_rsis_위로_올라옴"
                                #final_status += " " + type
                                #final_status_count += 1
                                self.writeFile(type, CODE, NAME, top, stock_weekly, status)

                if len(stock_weekly['volume']) > 6:
                    # BB 하단에 부딪힘
                    for c_index in range(1, 5):
                        if stock_weekly['bolingerband_lower'][c_index+1] is not None and stock_weekly['close'][c_index] <= (stock_weekly['bolingerband_lower'][c_index+1]):
                            type = "weekly_BB하단_내려옴"
                            final_status += " " + type
                            final_status_count += 1
                            self.writeFile(type, CODE, NAME, top, stock_weekly, status)
                            break




                # [Monthly]
                # 20주선이 40주 선을 상향 돌파함
                if len(stock_monthly['close']) > 40:
                    if (stock_monthly['avg6'][1] is not None and stock_monthly['avg36'][1] is not None and
                        stock_monthly['avg6'][0] is not None and stock_monthly['avg36'][0] is not None):
                        if stock_monthly['avg6'][1] <= stock_monthly['avg36'][1] and stock_monthly['avg6'][0] > stock_monthly['avg36'][0]:
                            type = "monthly_6월선_36월선_상향돌파"
                            final_status += " " + type
                            final_status_count += 1
                            self.writeFile(type, CODE, NAME, top, stock_weekly, status)

                # 종가가 20주선을 상향 돌파함
                if len(stock_monthly['close']) > 2:
                    if stock_monthly['close'][1] is not None and stock_monthly['avg12'][1] is not None and stock_monthly['close'][0] is not None and stock_monthly['avg12'][0] is not None:
                        if stock_monthly['close'][1] <= stock_monthly['avg12'][1] and stock_monthly['close'][0] > stock_monthly['avg12'][0]:
                            type = "monthly_종가_12월선_상향돌파"
                            final_status += " " + type
                            final_status_count += 1
                            self.writeFile(type, CODE, NAME, top, stock_weekly, status)

                # RSI가 32 이하인 경우 (30이 이하로 떨어지는 것 미리 확인)
                if len(stock_monthly['close']) > 1:
                    if stock_monthly['rsi'][0] is not None:
                        if stock_monthly['rsi'][0] <= 30:
                            type = "monthly_rsi_30이하"
                            final_status += " " + type
                            final_status_count += 1
                            self.writeFile(type, CODE, NAME, top, stock_weekly, status)

                # rsi가 rsis 아래에서 위로 올라올 때
                if len(stock_monthly['close']) > 60:
                    if stock_monthly['rsi'][0] is not None and stock_monthly['rsis'][0] is not None and stock_monthly['rsi'][1] is not None and stock_monthly['rsis'][1] is not None:
                        if stock_monthly['rsi'][0] < 40:
                            if stock_monthly['rsi'][0] > stock_monthly['rsis'][0] and stock_monthly['rsi'][1] <= stock_monthly['rsis'][1]:
                                type = "monthly_rsi_rsis_위로_올라옴"
                                #final_status += " " + type
                                #final_status_count += 1
                                self.writeFile(type, CODE, NAME, top, stock_monthly, status)

                if len(stock_monthly['volume']) > 5:
                    # BB 하단에 부딪힘
                    for c_index in range(1, 5):
                        if stock_monthly['bolingerband_lower'][c_index+1] is None:
                            break
                        if stock_monthly['close'][c_index] <= (stock_monthly['bolingerband_lower'][c_index+1]):
                            type = "monthly_BB하단_내려옴"
                            final_status += " " + type
                            final_status_count += 1
                            self.writeFile(type, CODE, NAME, top, stock_monthly, status)
                            break



                # 3) daily
                if len(stock_daily['volume']) > 5:
                    # RSI가 10 이하인 경우 (10이 이하로 떨어지는 것 미리 확인)
                    if stock_daily['rsi'][0] is not None:
                        if stock_daily['rsi'][0] <= 10:
                            type = "daily_rsi_10이하"
                            final_status += " " + type
                            final_status_count += 1
                            self.writeFile(type, CODE, NAME, top, stock_weekly, status)

                    # 2년 중 최대 거래량인 경우
                    size = len(stock_daily['volume'])
                    first_index = 520
                    if len(stock_daily['volume']) < first_index:
                        first_index = len(stock_daily['volume'])
                    valid = True
                    for c_index in range(size-first_index, size):
                        if stock_daily['volume'][c_index] > stock_daily['volume'][size-1]:
                            valid = False
                            break
                    if valid:
                        type = "daily_이전에_없던_거래량"
                        final_status += " " + type
                        final_status_count += 1
                        self.writeFile(type, CODE, NAME, top, stock_daily, status)
                        break

                    # BB 하단에 내려옴
                    for c_index in range(1, 5):
                        if stock_daily['bolingerband_lower'][c_index+1] is None:
                            break

                        if stock_daily['close'][c_index] <= (stock_daily['bolingerband_lower'][c_index + 1]):
                            type = "daily_BB하단_내려옴"
                            final_status += " " + type
                            final_status_count += 1
                            self.writeFile(type, CODE, NAME, top, stock_daily, status)
                            break

                    # 종가가 60일선을 상향 돌파함
                    if len(stock_daily['close']) > 60:
                        if stock_daily['close'][1] is not None and stock_daily['avg60'][1] is not None and stock_daily['close'][0] is not None and stock_daily['avg60'][0] is not None:
                            if stock_daily['close'][1] <= stock_daily['avg60'][1] and stock_daily['close'][0] > stock_daily['avg60'][0]:
                                type = "daily_종가_60일선_상향돌파"
                                final_status += " " + type
                                final_status_count += 1
                                self.writeFile(type, CODE, NAME, top, stock_daily, status)

                            # [Dailly]
                            if (stock_daily['avg3'][0] >= stock_daily['avg10'][0] and
                                    stock_daily['avg3'][1] <= stock_daily['avg10'][1] and
                                    stock_daily['avg3'][2] <= stock_daily['avg10'][2] and
                                    stock_daily['avg3'][3] <= stock_daily['avg10'][3]):
                                type = "daily_3일선_10일선_상향돌파"
                                final_status += " " + type
                                final_status_count += 1
                                self.writeFile(type, CODE, NAME, top, stock_weekly, status)

                            if (stock_daily['avg3'][0] <= stock_daily['avg10'][0] and
                                    stock_daily['avg3'][1] >= stock_daily['avg10'][1] and
                                    stock_daily['avg3'][2] >= stock_daily['avg10'][2] and
                                    stock_daily['avg3'][3] >= stock_daily['avg10'][3]):
                                type = "daily_3일선_10일선_하향돌파"
                                final_status += " " + type
                                final_status_count += 1
                                self.writeFile(type, CODE, NAME, top, stock_weekly, status)

            if final_status_count > 0:
                type = "final"
                self.writeFile(type, CODE, NAME, top, stock_daily, final_status, final_status_count)
        return

    def get_moving_average(self, stock):
        q_3 = MovingAverage(3)
        q_4 = MovingAverage(4)
        q_5 = MovingAverage(5)
        q_6 = MovingAverage(6)
        q_10 = MovingAverage(10)
        q_12 = MovingAverage(12)
        q_20 = MovingAverage(20)
        q_36 = MovingAverage(36)
        q_40 = MovingAverage(40)
        q_48 = MovingAverage(48)
        q_60 = MovingAverage(60)
        q_120 = MovingAverage(120)
        q_200 = MovingAverage(200)
        q_240 = MovingAverage(240)
        q_300 = MovingAverage(300)

        for i in range(len(stock)):
            q_3.enqueue(stock[i]['close'])
            q_4.enqueue(stock[i]['close'])
            q_5.enqueue(stock[i]['close'])
            q_6.enqueue(stock[i]['close'])
            q_10.enqueue(stock[i]['close'])
            q_12.enqueue(stock[i]['close'])
            q_20.enqueue(stock[i]['close'])
            q_36.enqueue(stock[i]['close'])
            q_40.enqueue(stock[i]['close'])
            q_48.enqueue(stock[i]['close'])
            q_60.enqueue(stock[i]['close'])
            q_120.enqueue(stock[i]['close'])
            q_200.enqueue(stock[i]['close'])
            q_240.enqueue(stock[i]['close'])
            q_300.enqueue(stock[i]['close'])

            stock[i]['avg3'] = q_3.avg()
            stock[i]['avg4'] = q_4.avg()
            stock[i]['avg5'] = q_5.avg()
            stock[i]['avg6'] = q_6.avg()
            stock[i]['avg10'] = q_10.avg()
            stock[i]['avg12'] = q_12.avg()
            stock[i]['avg20'] = q_20.avg()
            stock[i]['avg36'] = q_36.avg()
            stock[i]['avg40'] = q_40.avg()
            stock[i]['avg48'] = q_48.avg()
            stock[i]['avg60'] = q_60.avg()
            stock[i]['avg120'] = q_120.avg()
            stock[i]['avg200'] = q_200.avg()
            stock[i]['avg240'] = q_240.avg()
            stock[i]['avg300'] = q_300.avg()

        return

    def convertFormat(self, weekDict):
        previous_close = 0
        stock_price = []
        for ts in weekDict['open']:
            stock_price.append(
                {
                    "ymd": ts.strftime("%Y.%m.%d"),
                    "close": weekDict['close'][ts],
                    "diff": weekDict['close'][ts] - previous_close,
                    "open": weekDict['open'][ts],
                    "high": weekDict['high'][ts],
                    "low": weekDict['low'][ts],
                    "volume": weekDict['volume'][ts],
                    "avg3": -1,
                    "avg4": -1,
                    "avg5": -1,
                    "avg6": -1,
                    "avg10": -1,
                    "avg12": -1,
                    "avg20": -1,
                    "avg36": -1,
                    "avg40": -1,
                    "avg48": -1,
                    "avg60": -1,
                    "avg120": -1,
                    "avg200": -1,
                    "avg240": -1,
                    "avg300": -1,
                    "bolingerband_upper": -1,
                    "bolingerband_lower": -1,
                    "bolingerband_middle": -1,
                    "ichimokucloud_changeLine": -1,
                    "ichimokucloud_baseLine": -1,
                    "ichimokucloud_leadingSpan1": -1,
                    "ichimokucloud_leadingSpan2": -1,
                    "stochastic_fast_k": -1,
                    "stochastic_slow_k": -1,
                    "stochastic_slow_d": -1,
                    "rsi": -1,
                    "rsis": -1
                }
            )
            previous_close = weekDict['close'][ts]

        return stock_price

    def analyzeAdditionalInfo(self, stock, cursor, type=None):
        if type==None:
            stockAnalysisTableName = 'stock_analysis'
        else:
            stockAnalysisTableName = 'stock_analysis_' + type

        # 테이블 생성
        cursor.execute("CREATE TABLE IF NOT EXISTS " + stockAnalysisTableName + " (CODE text, NAME text, ymd text, close REAL, diff REAL, open REAL, high REAL, low REAL, volume REAL, avg3 REAL, avg4 REAL, avg5 REAL, avg6 REAL, avg10 REAL, avg12 REAL, avg20 REAL, avg36 REAL, avg40 REAL, avg48 REAL, avg60 REAL, avg120 REAL, avg200 REAL, avg240 REAL, avg300 REAL, bolingerband_upper REAL, bolingerband_lower REAL, bolingerband_middle REAL, ichimokucloud_changeLine REAL, ichimokucloud_baseLine REAL, ichimokucloud_leadingSpan1 REAL, ichimokucloud_leadingSpan2 REAL, stochastic_fast_k REAL, stochastic_slow_k REAL, stochastic_slow_d REAL, rsi REAL, rsis REAL)")

        # 키 생성
        create_key = "CREATE INDEX IF NOT EXISTS " + stockAnalysisTableName + "_idx on " + stockAnalysisTableName + " (CODE, ymd) "
        cursor.execute(create_key)

        # 이동 평균 계산
        stock["PRICE"] = sorted(stock["PRICE"], key=lambda x: x['ymd'])
        self.get_moving_average(stock["PRICE"])

        self.ichimokuCloud.analyze(stock)
        self.stochastic.analyze(stock)
        self.bolingerBand.analyze(stock)
        self.rsi.analyze(stock)

        sorted_stock = sorted(stock["PRICE"], key=lambda x: x['ymd'], reverse=True)
        for price in sorted_stock:
            cursor.execute('SELECT * FROM ' + stockAnalysisTableName + ' WHERE CODE=? and ymd=?', (stock['CODE'], price['ymd'],))
            result = cursor.fetchone()
            if result == None:
                sql = "INSERT INTO " + stockAnalysisTableName + "(CODE, NAME, ymd, close, diff, open, high, low, volume, "
                sql += " avg3, avg4, avg5, avg6, avg10, avg12, avg20, avg36, avg40, avg48, avg60, avg120, avg200, avg240, avg300, "
                sql += " bolingerband_upper, bolingerband_lower, bolingerband_middle, "
                sql += " ichimokucloud_changeLine, ichimokucloud_baseLine, ichimokucloud_leadingSpan1, ichimokucloud_leadingSpan2, "
                sql += " stochastic_fast_k, stochastic_slow_k, stochastic_slow_d, "
                sql += " rsi, rsis) "
                sql += " VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"

                cursor.execute(sql, (
                stock["CODE"], stock["NAME"], price['ymd'], price['close'], price['diff'], price['open'], price['high'], price['low'], price['volume'],
                price['avg3'], price['avg4'], price['avg5'], price['avg6'], price['avg10'], price['avg12'], price['avg20'], price['avg36'], price['avg40'], price['avg48'], price['avg60'], price['avg120'], price['avg200'], price['avg240'], price['avg300'],
                price['bolingerband_upper'], price['bolingerband_lower'], price['bolingerband_middle'],
                price['ichimokucloud_changeLine'], price['ichimokucloud_baseLine'], price['ichimokucloud_leadingSpan1'],
                price['ichimokucloud_leadingSpan2'],
                price['stochastic_fast_k'], price['stochastic_slow_k'], price['stochastic_slow_d'],
                price['rsi'], price['rsis'],))

            else:
                sql = "UPDATE " + stockAnalysisTableName + " SET close=?, diff=?, open=?, high=?, low=?, volume=?, "
                sql += " avg3=?, avg4=?, avg5=?, avg6=?, avg10=?, avg12=?, avg20=?, avg36=?, avg40=?, avg48=?, avg60=?, avg120=?, avg200=?, avg240=?, avg300=?, "
                sql += " bolingerband_upper=?, bolingerband_lower=?, bolingerband_middle=?, "
                sql += " ichimokucloud_changeLine=?, ichimokucloud_baseLine=?, ichimokucloud_leadingSpan1=?, ichimokucloud_leadingSpan2=?, "
                sql += " stochastic_fast_k=?, stochastic_slow_k=?, stochastic_slow_d=?, "
                sql += " rsi=?, rsis=? "
                sql += " WHERE CODE=? and ymd=?"

                cursor.execute(sql,
                    (price['close'], price['diff'], price['open'], price['high'], price['low'], price['volume'],
                     price['avg3'], price['avg4'], price['avg5'], price['avg6'], price['avg10'], price['avg12'], price['avg20'], price['avg36'], price['avg40'], price['avg48'], price['avg60'], price['avg120'], price['avg200'], price['avg240'], price['avg300'],
                     price['bolingerband_upper'], price['bolingerband_lower'], price['bolingerband_middle'], price['ichimokucloud_changeLine'], price['ichimokucloud_baseLine'],
                     price['ichimokucloud_leadingSpan1'], price['ichimokucloud_leadingSpan2'],
                     price['stochastic_fast_k'], price['stochastic_slow_k'], price['stochastic_slow_d'],
                     price['rsi'], price['rsis'],
                     stock["CODE"], price['ymd'],))
                break

        return

    def analyzeDaily(self):
        stockTableName = 'stock'

        conn = sqlite3.connect(self.stockFileName)
        cursor = conn.cursor()

        cursor.execute('SELECT distinct code, name FROM ' + stockTableName + ' order by code')
        items = cursor.fetchall()

        for rowid, item in enumerate(items):

            stock = {"CODE": item[0], "NAME": item[1], "PRICE":[]}
            print("Daily # :", rowid, ", CODE: ", stock['CODE'], ", NAME: ", stock['NAME'])

            sql = 'SELECT ymd, close, diff, open, high, low, volume FROM ' + stockTableName + ' where CODE=? order by ymd desc '
            #if result is not None:
            #    sql += ' limit 300'
            cursor.execute(sql, (stock['CODE'],))
            items = cursor.fetchall()

            items_reverse = reversed(items)
            for item in items_reverse:
                stock['PRICE'].append(
                    {"ymd": item[0],
                     "close": item[1],
                     "diff": item[2],
                     "open": item[3],
                     "high": item[4],
                     "low": item[5],
                     "volume": item[6],
                     "avg3": -1,
                     "avg4": -1,
                     "avg5": -1,
                     "avg6": -1,
                     "avg10": -1,
                     "avg12": -1,
                     "avg20": -1,
                     "avg36": -1,
                     "avg40": -1,
                     "avg48": -1,
                     "avg60": -1,
                     "avg120": -1,
                     "avg200": -1,
                     "avg240": -1,
                     "avg300": -1,
                     "bolingerband_upper": -1,
                     "bolingerband_lower": -1,
                     "bolingerband_middle": -1,
                     "ichimokucloud_changeLine": -1,
                     "ichimokucloud_baseLine": -1,
                     "ichimokucloud_leadingSpan1": -1,
                     "ichimokucloud_leadingSpan2": -1,
                     "stochastic_fast_k": -1,
                     "stochastic_slow_k": -1,
                     "stochastic_slow_d": -1,
                     "rsi": -1,
                     "rsis": -1})

            self.analyzeAdditionalInfo(stock, cursor)

        conn.commit()
        cursor.close()
        conn.close()

        return


    def analyzeGrouping(self, type):
        stockTableName = 'stock'

        conn = sqlite3.connect(self.stockFileName)
        cursor = conn.cursor()

        cursor.execute('SELECT distinct code, name FROM ' + stockTableName + ' order by code')
        items = cursor.fetchall()

        for rowid, item in enumerate(items):
            stock = {"CODE": item[0], "NAME": item[1], "PRICE": []}
            print(type, "# :", rowid, ", CODE: ", stock['CODE'], ", NAME: ", stock['NAME'])

            sql = 'SELECT ymd, close, diff, open, high, low, volume FROM ' + stockTableName + ' where CODE=? order by ymd desc '
            cursor.execute(sql, (stock['CODE'],))
            items = cursor.fetchall()

            items_reverse = reversed(items)
            for item in items_reverse:
                stock['PRICE'].append(
                    {"ymd": item[0],
                     "close": item[1],
                     "diff": item[2],
                     "open": item[3],
                     "high": item[4],
                     "low": item[5],
                     "volume": item[6],
                     "avg3": -1,
                     "avg4": -1,
                     "avg5": -1,
                     "avg6": -1,
                     "avg10": -1,
                     "avg12": -1,
                     "avg20": -1,
                     "avg36": -1,
                     "avg40": -1,
                     "avg48": -1,
                     "avg60": -1,
                     "avg120": -1,
                     "avg200": -1,
                     "avg240": -1,
                     "avg300": -1,
                     "bolingerband_upper": -1,
                     "bolingerband_lower": -1,
                     "bolingerband_middle": -1,
                     "ichimokucloud_changeLine": -1,
                     "ichimokucloud_baseLine": -1,
                     "ichimokucloud_leadingSpan1": -1,
                     "ichimokucloud_leadingSpan2": -1,
                     "stochastic_fast_k": -1,
                     "stochastic_slow_k": -1,
                     "stochastic_slow_d": -1,
                     "rsi": -1,
                     "rsis": -1})

            agg_dict = {'open': 'first',
                        'high': 'max',
                        'low': 'min',
                        'close': 'last',
                        'volume': 'sum'}

            df = pd.DataFrame(stock['PRICE'])
            df['ymd'] = pd.to_datetime(df['ymd'])
            df.set_index('ymd', inplace=True)

            if type == "weekly":
                condition="W"
            else:
                condition='M'
            df_group = df.resample(condition).agg(agg_dict)
            df_group = df_group.dropna()
            df_group.merge(df, )
            stock['PRICE'] = self.convertFormat(df_group.to_dict())

            self.analyzeAdditionalInfo(stock, cursor, type)

        conn.commit()
        cursor.close()
        conn.close()

        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__))))))

    stockFileName = PROJECT_HOME + '/resources/stock.db'
    analyzer = AnalyzerSqlite(PROJECT_HOME, stockFileName)

    #analyzer.analyzeDaily()
    #analyzer.analyzeGrouping("weekly")
    #analyzer.analyzeGrouping("monthly")

    # 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")
    outPath = os.path.join(outPath, day)
    if os.path.isdir(outPath):
        shutil.rmtree(outPath)
    os.mkdir(outPath)
    print("print to Html...")
    analyzer.findCandidate(outPath)

    print("time : %6.2f 초" % (time.time() - start))

    print("done...")

