├── 01_Stock_Investment ├── ch01_01_SamsungElectronics.py └── imgs │ ├── BerkshireHathaway.png │ ├── Figure_1.png │ ├── Kyungsung_exchange.jpg │ ├── SamsungElectronics.jpg │ ├── Screenshot20171121.png │ ├── TheIntelligentInvestor.jpg │ ├── VOC.PNG │ └── ecos_kospi.png ├── 02_Python_Programming ├── ch02_01_ImageProcessing.py ├── imgs │ ├── ImageProcessing.jpg │ ├── PillowShow.jpg │ ├── ch02_Anaconda.jpg │ ├── ch02_HelloWorld.jpg │ ├── ch02_IDLE.jpg │ ├── ch02_PyPI.jpg │ ├── ch02_PythonInstallation1.jpg │ ├── ch02_PythonInstallation2.jpg │ ├── ch02_PythonInstallation3.jpg │ ├── ch02_PythonInstallation4.jpg │ ├── ch02_PythonPath1.jpg │ ├── ch02_PythonPath2.jpg │ ├── ch02_PythonPath3.jpg │ ├── ch02_PythonPath4.jpg │ ├── ch02_PythonPath5.jpg │ ├── ch02_PythonPath6.jpg │ ├── ch02_Requests.jpg │ ├── ch02_VEnv1.jpg │ ├── ch02_VEnv2.jpg │ ├── ch02_VEnv3.jpg │ ├── ch02_VEnv4.jpg │ ├── ch02_VEnv5.jpg │ ├── ch02_VEnv6.jpg │ ├── ch02_VEnv7.jpg │ ├── ch02_pycache.jpg │ ├── dst.png │ ├── pycache.png │ └── src.png └── requirements.txt ├── 03_NumPy_and_Pandas ├── ch03_00_CumulativeProduct.py ├── ch03_01_KOSPI_MDD.py ├── ch03_02_DowKospi_Scatter.py ├── ch03_03_DowKospi_Regression.py └── imgs │ ├── ElliottWave.jpg │ ├── InnerProduct.jpg │ ├── SecHist.jpg │ ├── kospi_dow.jpg │ ├── kospi_dow_indexation.jpg │ ├── kospi_dow_regr.jpg │ ├── kospi_dow_scatter.jpg │ ├── kospi_tlt_regr.jpg │ ├── max_dd.jpg │ └── pandas.png ├── 04_Web_Scraping ├── HtmlSample.htm ├── ch04_01_Celltrion_PlotChart.py ├── ch04_02_Celltrion_CandleChart_OldSchool.py ├── ch04_03_Celltrion_CandleChart_NewSchool.py └── imgs │ ├── CandleChart.jpg │ ├── CelltrionURL.jpg │ ├── Celltrion_CandleChart_NewSchool.jpg │ ├── Celltrion_CandleStickChart_OldSchool.jpg │ ├── Celltrion_CustomizedCandleChart_NewSchool.jpg │ ├── Celltrion_OhlcChart_NewSchool.jpg │ ├── Celltrion_close.jpg │ ├── HtmlSample.jpg │ ├── OhlcCandleChart.jpg │ ├── bs4.jpg │ ├── kind.jpg │ ├── kind_excel.jpg │ ├── kind_notepad.jpg │ ├── sise1.jpg │ └── sise2.jpg ├── 05_Stock_Price_API ├── Investar │ ├── Analyzer.py │ ├── DBUpdater.py │ ├── DBUpdaterEx.py │ └── MarketDB.py ├── ch05_01_YahooFinance_SEC.py ├── ch05_02_NaverDatabase_SEC.py ├── ch05_03_SelectVersion.py ├── ch05_04_CreateTable.sql └── imgs │ ├── API_Client1.jpg │ ├── API_Client2.jpg │ ├── API_ConfigJson.jpg │ ├── API_ConfigMy.jpg │ ├── API_DBUpdater.jpg │ ├── API_DBUpdater1.jpg │ ├── API_DBUpdater2.jpg │ ├── API_Download2.jpg │ ├── API_GetDailyPrice.jpg │ ├── API_HeidiSQL1.jpg │ ├── API_HeidiSQL2.jpg │ ├── API_HeidiSQL3.jpg │ ├── API_HeidiSQL4.jpg │ ├── API_HeidiSQL5.jpg │ ├── API_Installer.jpg │ ├── API_Installer2.jpg │ ├── API_Installer3.jpg │ ├── API_RunRegistry.jpg │ ├── DBUpdaterEx.jpg │ ├── DBUpdaterEx2024-03-03.png │ ├── DBUpdaterEx_2024-06-30.jpg │ ├── ExceptionOccured_2024-06-30.jpg │ ├── GetDailyPrice.png │ ├── HeidiSQL.png │ ├── MTV2.png │ ├── MariaDB_Download.jpg │ ├── MariaDB_DownloadPage.jpg │ └── MariaDB_IndexPage.jpg ├── 06_Trading_Strategy ├── ch06_01_EfficientFrontier.py ├── ch06_02_PortfolioOptimization.py ├── ch06_03_BollingerBand.py ├── ch06_04_BollingerBand_PercentB.py ├── ch06_05_BollingerBand_BandWidth.py ├── ch06_06_BollingerBand_TrendFollowing.py ├── ch06_07_BollingerBand_IIP21.py ├── ch06_08_BollingerBand_Reversals.py ├── ch06_09_FirstScreen.py ├── ch06_09_FirstScreenEx.py ├── ch06_10_SecondScreen.py ├── ch06_11_TripleScreen.py ├── ch06_12_DualMomentum.py └── imgs │ ├── AbsoluteMomentum.jpg │ ├── BollingerBand.jpg │ ├── BollingerBand_BandWidth.jpg │ ├── BollingerBand_IIP21.jpg │ ├── BollingerBand_MFI.jpg │ ├── BollingerBand_PercentB.jpg │ ├── BollingerBand_Reversals.jpg │ ├── BollingerBand_TrendFollowing.jpg │ ├── BollingerBand_TrendFollowing_Naver.jpg │ ├── BollingerOnBollingerBands.jpg │ ├── DualMomentum.jpg │ ├── DualMomentumInvesting.jpg │ ├── FirstScreen.jpg │ ├── Long-TermSecretsToShort-TermTrading.jpg │ ├── Portpolio_optimization.jpg │ ├── RelativeMomentum.jpg │ ├── SecondScreen.jpg │ ├── TheNewTradingForALiving.jpg │ ├── TripleScreen.jpg │ ├── ch06_EfficientFrontierLine.jpg │ └── efficient_frontier.jpg ├── 07_Django_and_Automation ├── ch07_01_index.html ├── ch07_02_index.html ├── ch07_03_style.css ├── ch07_04_balance_views.py ├── ch07_05_balance.html ├── ch07_06_b_style.css ├── ch07_07_Slack_SendMessage.py ├── ch07_08_Backtrader_RSI.py ├── ch07_09_Backtrader_RSI_SMA.py └── imgs │ ├── BackTrader_PlotRSISMA.jpg │ ├── Backtrader_Homepage.jpg │ ├── Backtrader_PlotRSI.jpg │ ├── Balance_Naver.jpg │ ├── Balance_Sample2.jpg │ ├── Django_AdminLogin.jpg │ ├── Django_AdminPage.jpg │ ├── Django_Hello.jpg │ ├── Django_Homepage.jpg │ ├── Django_IndexPage.jpg │ ├── Django_IndexTree.jpg │ ├── Django_Logo.jpg │ ├── Django_PIP.jpg │ ├── Django_Python.jpg │ ├── Django_Rocket.jpg │ ├── Django_StaticImage.jpg │ ├── Django_Superuser.jpg │ ├── Django_Tree.jpg │ ├── Slack_Bots.jpg │ ├── Slack_CreateApp.jpg │ ├── Slack_Scopes.jpg │ ├── Slack_SmartPhone.png │ └── Slack_mySlackBot.jpg ├── 08_Volatility_Breakout ├── ch08_01_AutoConnect.py ├── ch08_02_DynamicPageScraping_NaverETF.py ├── ch08_03_EtfAlgoTrader.py └── imgs │ ├── NaverFinance_Naver.jpg │ ├── VB_ConfirmOrder.jpg │ ├── VB_CreonBalance.jpg │ ├── VB_CreonDownload.jpg │ ├── VB_CreonPlusTray.jpg │ ├── VB_CreonPlustLogin.jpg │ ├── VB_CurrentPrice.jpg │ ├── VB_EtfAlogTraderLog.jpg │ ├── VB_EtfSise.jpg │ ├── VB_HeadlessChrome.jpg │ ├── VB_IdleAdmin.jpg │ ├── VB_JobExecute.jpg │ ├── VB_JobName.jpg │ ├── VB_JobOperation.jpg │ ├── VB_JobScheduler.jpg │ ├── VB_JobTrigger.jpg │ ├── VB_OHLC.jpg │ ├── VB_PythonAdmin.jpg │ ├── VB_PythonwAdmin.jpg │ ├── VB_SlackMessage.jpg │ ├── VB_TigerHoga.jpg │ ├── VB_TigerSise.jpg │ ├── VB_Trigger.jpg │ ├── VB_VolatilityBreakout.jpg │ ├── VB_WinSearch.jpg │ ├── VolatilityBreakout.jpg │ └── yahoo_finance.jpg ├── 09_Deep_Learning_Prediction ├── ch09_01_StepFunction.py ├── ch09_02_SigmoidFunction.py ├── ch09_03_TanhFunction.py ├── ch09_04_ReLUFunction.py ├── ch09_05_SoftmaxFunction.py ├── ch09_06_MLP_HiddenLayer.py ├── ch09_07_MLP_OutputLayer.py ├── ch09_08_LinearRegression.py ├── ch09_09_RNN_StockPrediction.py └── imgs │ ├── AI_Difference.jpg │ ├── AI_LR_Step1.jpg │ ├── AI_LR_Step2.jpg │ ├── AI_LR_Step3.jpg │ ├── AI_LR_Step4.jpg │ ├── AI_LR_Step5.jpg │ ├── AI_LR_Step6.jpg │ ├── AI_LTSM1.jpg │ ├── AI_LTSM2.jpg │ ├── AI_MLP.jpg │ ├── AI_PerceptronImage.jpg │ ├── AI_RNN.jpg │ ├── AI_ReLUFunc.jpg │ ├── AI_SigmoidFunc.jpg │ ├── AI_StepFunc.jpg │ ├── AI_StockPricePrediction.jpg │ ├── AI_StockPricePrediction_Cmd.jpg │ └── AI_TanhFunc.jpg ├── 10_Appendix_(Python_Built-in_Functions_and_AES-256_Encryption).pdf ├── PowerPoint_Materials.pptx └── README.md /01_Stock_Investment/ch01_01_SamsungElectronics.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | from Investar import Analyzer 3 | 4 | mk = Analyzer.MarketDB() 5 | df = mk.get_daily_price('삼성전자', '1998-04-27', '2018-04-27') 6 | """ 7 | >>> df 8 | code date open ... volume MA20 MA200 9 | date ... 10 | 1998-04-27 005930 1998-04-27 66800 ... 187010 NaN NaN 11 | 1998-04-28 005930 1998-04-28 65000 ... 174220 NaN NaN 12 | 1998-04-29 005930 1998-04-29 66900 ... 238910 NaN NaN 13 | 1998-04-30 005930 1998-04-30 70500 ... 616240 NaN NaN 14 | 1998-05-02 005930 1998-05-02 72000 ... 236600 NaN NaN 15 | ... ... ... ... ... ... ... ... 16 | 2018-04-23 005930 2018-04-23 2550000 ... 232380 2478450.0 2513175.0 17 | 2018-04-24 005930 2018-04-24 2592000 ... 315406 2479650.0 2513805.0 18 | 2018-04-25 005930 2018-04-25 2461000 ... 332292 2483900.0 2514520.0 19 | 2018-04-26 005930 2018-04-26 2521000 ... 360931 2491650.0 2515750.0 20 | 2018-04-27 005930 2018-04-27 2669000 ... 606216 2501100.0 2517250.0 21 | 22 | [4967 rows x 10 columns] 23 | """ 24 | df['MA20'] = df['close'].rolling(window=20).mean() 25 | df['MA200'] = df['close'].rolling(window=200).mean() 26 | 27 | plt.figure(figsize=(9, 7)) 28 | plt.plot(df.index, df['close'], color='cyan', label='Close') 29 | plt.plot(df.index, df['MA20'], 'm--', label='MA20') 30 | plt.plot(df.index, df['MA200'], 'r--', label='MA200') 31 | plt.legend(loc='best') 32 | plt.title('Samsung Electronics') 33 | plt.grid(color='gray', linestyle='--') 34 | plt.yticks([65300, 500000, 1000000, 1500000, 2000000, 2500000, 2650000]) 35 | plt.xticks(['1998-04-27', '2002-04-27', '2006-04-27', '2010-04-27', '2014-04-27', '2018-04-27']) 36 | plt.show() 37 | -------------------------------------------------------------------------------- /01_Stock_Investment/imgs/BerkshireHathaway.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/01_Stock_Investment/imgs/BerkshireHathaway.png -------------------------------------------------------------------------------- /01_Stock_Investment/imgs/Figure_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/01_Stock_Investment/imgs/Figure_1.png -------------------------------------------------------------------------------- /01_Stock_Investment/imgs/Kyungsung_exchange.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/01_Stock_Investment/imgs/Kyungsung_exchange.jpg -------------------------------------------------------------------------------- /01_Stock_Investment/imgs/SamsungElectronics.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/01_Stock_Investment/imgs/SamsungElectronics.jpg -------------------------------------------------------------------------------- /01_Stock_Investment/imgs/Screenshot20171121.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/01_Stock_Investment/imgs/Screenshot20171121.png -------------------------------------------------------------------------------- /01_Stock_Investment/imgs/TheIntelligentInvestor.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/01_Stock_Investment/imgs/TheIntelligentInvestor.jpg -------------------------------------------------------------------------------- /01_Stock_Investment/imgs/VOC.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/01_Stock_Investment/imgs/VOC.PNG -------------------------------------------------------------------------------- /01_Stock_Investment/imgs/ecos_kospi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/01_Stock_Investment/imgs/ecos_kospi.png -------------------------------------------------------------------------------- /02_Python_Programming/ch02_01_ImageProcessing.py: -------------------------------------------------------------------------------- 1 | import requests 2 | from PIL import Image 3 | import hashlib 4 | import matplotlib.pyplot as plt 5 | import matplotlib.image as mpimg 6 | 7 | # 2.8.1 리퀘스트로 인터넷에서 이미지 파일 가져오기 8 | # url = 'http://bit.ly/2JnsHnT' 9 | url = 'http://bit.ly/3ZZyeXQ' 10 | r = requests.get(url, stream=True).raw 11 | 12 | # 2.8.2 필로우로 이미지 보여주기 13 | img = Image.open(r) 14 | print("img : ", img.get_format_mimetype) 15 | img.show() 16 | img.save('src.png') 17 | 18 | # 2.8.3 'with ~ as 파일 객체:'로 이미지 파일 복사 19 | BUF_SIZE = 1024 20 | with open('src.png', 'rb') as sf, open('dst.png', 'wb') as df: 21 | while True: 22 | data = sf.read(BUF_SIZE) 23 | if not data: 24 | break 25 | df.write(data) 26 | 27 | # 2.8.4 SHA-256으로 파일 복사 검증하기 28 | sha_src = hashlib.sha256() 29 | sha_dst = hashlib.sha256() 30 | 31 | with open('src.png', 'rb') as sf, open('dst.png', 'rb') as df: 32 | sha_src.update(sf.read()) 33 | sha_dst.update(df.read()) 34 | 35 | print("src.png's hash : {}".format(sha_src.hexdigest())) 36 | print("dsc.png's hash : {}".format(sha_dst.hexdigest())) 37 | 38 | # 2.8.5 맷플롯립으로 이미지 가공하기 39 | plt.suptitle('Image Processing', fontsize=18) 40 | plt.subplot(1, 2, 1) # 1행 2열의 영역에서 첫 번째 영역으로 지정 41 | plt.title('Original Image') 42 | plt.imshow(mpimg.imread('src.png')) # 원본 파일을 읽어서 이미지로 표시 43 | 44 | plt.subplot(122) # 1행 2열의 영역에서 두 번째 영역으로 지정 45 | plt.title('Pseudocolor Image') 46 | dst_img = mpimg.imread('dst.png') 47 | pseudo_img = dst_img [:, :, 0] # 의사 색상 적용 48 | plt.imshow(pseudo_img) 49 | plt.show() 50 | 51 | 52 | -------------------------------------------------------------------------------- /02_Python_Programming/imgs/ImageProcessing.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/02_Python_Programming/imgs/ImageProcessing.jpg -------------------------------------------------------------------------------- /02_Python_Programming/imgs/PillowShow.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/02_Python_Programming/imgs/PillowShow.jpg -------------------------------------------------------------------------------- /02_Python_Programming/imgs/ch02_Anaconda.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/02_Python_Programming/imgs/ch02_Anaconda.jpg -------------------------------------------------------------------------------- /02_Python_Programming/imgs/ch02_HelloWorld.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/02_Python_Programming/imgs/ch02_HelloWorld.jpg -------------------------------------------------------------------------------- /02_Python_Programming/imgs/ch02_IDLE.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/02_Python_Programming/imgs/ch02_IDLE.jpg -------------------------------------------------------------------------------- /02_Python_Programming/imgs/ch02_PyPI.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/02_Python_Programming/imgs/ch02_PyPI.jpg -------------------------------------------------------------------------------- /02_Python_Programming/imgs/ch02_PythonInstallation1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/02_Python_Programming/imgs/ch02_PythonInstallation1.jpg -------------------------------------------------------------------------------- /02_Python_Programming/imgs/ch02_PythonInstallation2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/02_Python_Programming/imgs/ch02_PythonInstallation2.jpg -------------------------------------------------------------------------------- /02_Python_Programming/imgs/ch02_PythonInstallation3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/02_Python_Programming/imgs/ch02_PythonInstallation3.jpg -------------------------------------------------------------------------------- /02_Python_Programming/imgs/ch02_PythonInstallation4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/02_Python_Programming/imgs/ch02_PythonInstallation4.jpg -------------------------------------------------------------------------------- /02_Python_Programming/imgs/ch02_PythonPath1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/02_Python_Programming/imgs/ch02_PythonPath1.jpg -------------------------------------------------------------------------------- /02_Python_Programming/imgs/ch02_PythonPath2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/02_Python_Programming/imgs/ch02_PythonPath2.jpg -------------------------------------------------------------------------------- /02_Python_Programming/imgs/ch02_PythonPath3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/02_Python_Programming/imgs/ch02_PythonPath3.jpg -------------------------------------------------------------------------------- /02_Python_Programming/imgs/ch02_PythonPath4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/02_Python_Programming/imgs/ch02_PythonPath4.jpg -------------------------------------------------------------------------------- /02_Python_Programming/imgs/ch02_PythonPath5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/02_Python_Programming/imgs/ch02_PythonPath5.jpg -------------------------------------------------------------------------------- /02_Python_Programming/imgs/ch02_PythonPath6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/02_Python_Programming/imgs/ch02_PythonPath6.jpg -------------------------------------------------------------------------------- /02_Python_Programming/imgs/ch02_Requests.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/02_Python_Programming/imgs/ch02_Requests.jpg -------------------------------------------------------------------------------- /02_Python_Programming/imgs/ch02_VEnv1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/02_Python_Programming/imgs/ch02_VEnv1.jpg -------------------------------------------------------------------------------- /02_Python_Programming/imgs/ch02_VEnv2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/02_Python_Programming/imgs/ch02_VEnv2.jpg -------------------------------------------------------------------------------- /02_Python_Programming/imgs/ch02_VEnv3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/02_Python_Programming/imgs/ch02_VEnv3.jpg -------------------------------------------------------------------------------- /02_Python_Programming/imgs/ch02_VEnv4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/02_Python_Programming/imgs/ch02_VEnv4.jpg -------------------------------------------------------------------------------- /02_Python_Programming/imgs/ch02_VEnv5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/02_Python_Programming/imgs/ch02_VEnv5.jpg -------------------------------------------------------------------------------- /02_Python_Programming/imgs/ch02_VEnv6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/02_Python_Programming/imgs/ch02_VEnv6.jpg -------------------------------------------------------------------------------- /02_Python_Programming/imgs/ch02_VEnv7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/02_Python_Programming/imgs/ch02_VEnv7.jpg -------------------------------------------------------------------------------- /02_Python_Programming/imgs/ch02_pycache.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/02_Python_Programming/imgs/ch02_pycache.jpg -------------------------------------------------------------------------------- /02_Python_Programming/imgs/dst.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/02_Python_Programming/imgs/dst.png -------------------------------------------------------------------------------- /02_Python_Programming/imgs/pycache.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/02_Python_Programming/imgs/pycache.png -------------------------------------------------------------------------------- /02_Python_Programming/imgs/src.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/02_Python_Programming/imgs/src.png -------------------------------------------------------------------------------- /02_Python_Programming/requirements.txt: -------------------------------------------------------------------------------- 1 | absl-py==0.9.0 2 | asgiref==3.2.7 3 | astunparse==1.6.3 4 | backtrader==1.9.74.123 5 | beautifulsoup4==4.8.2 6 | bs4==0.0.1 7 | cachetools==4.1.0 8 | certifi==2019.11.28 9 | chardet==3.0.4 10 | cycler==0.10.0 11 | Django==3.0.2 12 | gast==0.3.3 13 | google-auth==1.13.1 14 | google-auth-oauthlib==0.4.1 15 | google-pasta==0.2.0 16 | grpcio==1.28.1 17 | h5py==2.10.0 18 | idna==2.8 19 | Keras-Preprocessing==1.1.0 20 | kiwisolver==1.1.0 21 | lxml==4.4.2 22 | Markdown==3.2.1 23 | matplotlib==3.1.2 24 | mplfinance==0.12.3a3 25 | multitasking==0.0.9 26 | numpy==1.17.4 27 | oauthlib==3.1.0 28 | opt-einsum==3.2.0 29 | pandas==1.0.1 30 | pandas-datareader==0.8.1 31 | Pillow==7.0.0 32 | protobuf==3.11.3 33 | pyasn1==0.4.8 34 | pyasn1-modules==0.2.8 35 | PyMySQL==0.9.3 36 | pyparsing==2.4.5 37 | python-dateutil==2.8.1 38 | pytz==2019.3 39 | requests==2.22.0 40 | requests-oauthlib==1.3.0 41 | rsa==4.0 42 | scipy==1.4.1 43 | selenium==3.141.0 44 | six==1.13.0 45 | slacker==0.13.0 46 | soupsieve==1.9.5 47 | sqlparse==0.3.0 48 | tensorboard==2.2.0 49 | tensorboard-plugin-wit==1.6.0.post3 50 | tensorflow==2.2.0 51 | tensorflow-estimator==2.2.0 52 | termcolor==1.1.0 53 | urllib3==1.25.7 54 | Werkzeug==1.0.1 55 | wrapt==1.12.1 56 | yfinance==0.1.54 57 | -------------------------------------------------------------------------------- /03_NumPy_and_Pandas/ch03_00_CumulativeProduct.py: -------------------------------------------------------------------------------- 1 | from pandas_datareader import data as pdr 2 | import yfinance as yf 3 | yf.pdr_override() 4 | 5 | sec = pdr.get_data_yahoo('005930.KS', start='2018-05-04') 6 | sec_dpc = (sec['Close']-sec['Close'].shift(1)) / sec['Close'].shift(1) * 100 7 | sec_dpc.iloc[0] = 0 # 일간 변동률의 첫 번째 값인 NaN을 0으로 변경한다. 8 | sec_dpc_cp = ((100+sec_dpc)/100).cumprod()*100-100 # 일간 변동률 누적곱 계산 9 | 10 | msft = pdr.get_data_yahoo('MSFT', start='2018-05-04') 11 | msft_dpc = (msft['Close'] / msft['Close'].shift(1) -1) * 100 12 | msft_dpc.iloc[0] = 0 13 | msft_dpc_cp = ((100+msft_dpc)/100).cumprod()*100-100 14 | 15 | import matplotlib.pyplot as plt 16 | plt.plot(sec.index, sec_dpc_cp, 'b', label='Samsung Electronics') 17 | plt.plot(msft.index, msft_dpc_cp, 'r--', label='Microsoft') 18 | plt.ylabel('Change %') 19 | plt.grid(True) 20 | plt.legend(loc='best') 21 | plt.show() 22 | -------------------------------------------------------------------------------- /03_NumPy_and_Pandas/ch03_01_KOSPI_MDD.py: -------------------------------------------------------------------------------- 1 | from pandas_datareader import data as pdr 2 | import yfinance as yf 3 | yf.pdr_override() 4 | import matplotlib.pyplot as plt 5 | 6 | kospi = pdr.get_data_yahoo('^KS11', '2004-01-04') 7 | 8 | window = 252 9 | peak = kospi['Adj Close'].rolling(window, min_periods=1).max() 10 | drawdown = kospi['Adj Close']/peak - 1.0 11 | max_dd = drawdown.rolling(window, min_periods=1).min() 12 | 13 | plt.figure(figsize=(9, 7)) 14 | plt.subplot(211) 15 | kospi['Close'].plot(label='KOSPI', title='KOSPI MDD', grid=True, legend=True) 16 | plt.subplot(212) 17 | drawdown.plot(c='blue', label='KOSPI DD', grid=True, legend=True) 18 | max_dd.plot(c='red', label='KOSPI MDD', grid=True, legend=True) 19 | plt.show() 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /03_NumPy_and_Pandas/ch03_02_DowKospi_Scatter.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | from pandas_datareader import data as pdr 3 | import yfinance as yf 4 | yf.pdr_override() 5 | 6 | dow = pdr.get_data_yahoo('^DJI', '2000-01-04') 7 | kospi = pdr.get_data_yahoo('^KS11', '2000-01-04') 8 | 9 | df = pd.DataFrame({'DOW': dow['Close'], 'KOSPI': kospi['Close']}) 10 | df = df.fillna(method='bfill') 11 | df = df.fillna(method='ffill') 12 | 13 | import matplotlib.pyplot as plt 14 | plt.figure(figsize=(7, 7)) 15 | plt.scatter(df['DOW'], df['KOSPI'], marker='.') 16 | plt.xlabel('Dow Jones Industrial Average') 17 | plt.ylabel('KOSPI') 18 | plt.show() 19 | -------------------------------------------------------------------------------- /03_NumPy_and_Pandas/ch03_03_DowKospi_Regression.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | from pandas_datareader import data as pdr 3 | import yfinance as yf 4 | yf.pdr_override() 5 | from scipy import stats 6 | import matplotlib.pylab as plt 7 | 8 | dow = pdr.get_data_yahoo('^DJI', '2000-01-04') 9 | kospi = pdr.get_data_yahoo('^KS11', '2000-01-04') 10 | 11 | df = pd.DataFrame({'X':dow['Close'], 'Y':kospi['Close']}) 12 | df = df.fillna(method='bfill') 13 | df = df.fillna(method='ffill') 14 | 15 | regr = stats.linregress(df.X, df.Y) 16 | regr_line = f'Y = {regr.slope:2f} X + {regr.intercept:2f}' 17 | 18 | plt.figure(figsize=(7, 7)) 19 | plt.plot(df.X, df.Y, '.') 20 | plt.plot(df.X, regr.slope * df.X + regr.intercept, 'r') 21 | plt.legend(['DOW x KOSPI', regr_line]) 22 | plt.title(f'DOW x KOSPI (R = {regr.rvalue:2f})') 23 | plt.xlabel('Dow Jones Industrial Average') 24 | plt.ylabel('KOSPI') 25 | plt.show() 26 | -------------------------------------------------------------------------------- /03_NumPy_and_Pandas/imgs/ElliottWave.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/03_NumPy_and_Pandas/imgs/ElliottWave.jpg -------------------------------------------------------------------------------- /03_NumPy_and_Pandas/imgs/InnerProduct.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/03_NumPy_and_Pandas/imgs/InnerProduct.jpg -------------------------------------------------------------------------------- /03_NumPy_and_Pandas/imgs/SecHist.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/03_NumPy_and_Pandas/imgs/SecHist.jpg -------------------------------------------------------------------------------- /03_NumPy_and_Pandas/imgs/kospi_dow.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/03_NumPy_and_Pandas/imgs/kospi_dow.jpg -------------------------------------------------------------------------------- /03_NumPy_and_Pandas/imgs/kospi_dow_indexation.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/03_NumPy_and_Pandas/imgs/kospi_dow_indexation.jpg -------------------------------------------------------------------------------- /03_NumPy_and_Pandas/imgs/kospi_dow_regr.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/03_NumPy_and_Pandas/imgs/kospi_dow_regr.jpg -------------------------------------------------------------------------------- /03_NumPy_and_Pandas/imgs/kospi_dow_scatter.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/03_NumPy_and_Pandas/imgs/kospi_dow_scatter.jpg -------------------------------------------------------------------------------- /03_NumPy_and_Pandas/imgs/kospi_tlt_regr.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/03_NumPy_and_Pandas/imgs/kospi_tlt_regr.jpg -------------------------------------------------------------------------------- /03_NumPy_and_Pandas/imgs/max_dd.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/03_NumPy_and_Pandas/imgs/max_dd.jpg -------------------------------------------------------------------------------- /03_NumPy_and_Pandas/imgs/pandas.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/03_NumPy_and_Pandas/imgs/pandas.png -------------------------------------------------------------------------------- /04_Web_Scraping/HtmlSample.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | This is title. 4 | 5 | 6 |

This is heading1 text.

7 |

This is heading2 text.

8 |

This is heading3 text.

9 |

This is a paragraph.

10 | This is plain text.
11 | This is bold text.
12 | This is Italic text.
13 | This is strike text.
14 |
    15 |
  1. the first orderd list
  2. 16 |
  3. the second orderd list
  4. 17 |
  5. the third orderd list
  6. 18 |
19 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 |
table header 1table header 2table header 3
table data 4table data 5table data 6
table data 7table data 8table data 9

41 | 42 | Visit Python homepage!
43 |
44 | 45 | 46 | -------------------------------------------------------------------------------- /04_Web_Scraping/ch04_01_Celltrion_PlotChart.py: -------------------------------------------------------------------------------- 1 | # ch04_01_Celltrion_PlotChart.py 2 | import pandas as pd 3 | import requests 4 | from bs4 import BeautifulSoup 5 | from matplotlib import pyplot as plt 6 | 7 | # 4.4.3 맨 뒤 페이지 숫자 구하기 8 | url = 'https://finance.naver.com/item/sise_day.nhn?code=068270&page=1' 9 | html = requests.get(url, headers={'User-agent': 'Mozilla/5.0'}).text 10 | bs = BeautifulSoup(html, 'lxml') 11 | pgrr = bs.find('td', class_='pgRR') 12 | s = str(pgrr.a['href']).split('=') 13 | last_page = s[-1] 14 | 15 | # 4.4.4 전체 페이지 읽어오기 16 | df = pd.DataFrame() 17 | sise_url = 'https://finance.naver.com/item/sise_day.nhn?code=068270' 18 | for page in range(1, int(last_page)+1): 19 | url = '{}&page={}'.format(sise_url, page) 20 | html = requests.get(url, headers={'User-agent': 'Mozilla/5.0'}).text 21 | df = df.append(pd.read_html(html, header=0)[0]) 22 | 23 | # 차트 출력을 위해 데이터프레임 가공하기 24 | df = df.dropna() 25 | df = df.iloc[0:30] # ① 26 | df = df.sort_values(by='날짜') # ② 27 | 28 | # 날짜, 종가 컬럼으로 차트 그리기 29 | plt.title('Celltrion (close)') 30 | plt.xticks(rotation=45) # ③ 31 | plt.plot(df['날짜'], df['종가'], 'co-') # ④ 32 | plt.grid(color='gray', linestyle='--') 33 | plt.show() 34 | -------------------------------------------------------------------------------- /04_Web_Scraping/ch04_02_Celltrion_CandleChart_OldSchool.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | from urllib.request import urlopen 3 | from bs4 import BeautifulSoup 4 | from matplotlib import pyplot as plt 5 | from matplotlib import dates as mdates 6 | from mpl_finance import candlestick_ohlc 7 | #from mplfinance.original_flavor import candlestick_ohlc 8 | from datetime import datetime 9 | 10 | url = 'https://finance.naver.com/item/sise_day.nhn?code=068270&page=1' 11 | with urlopen(url) as doc: 12 | html = BeautifulSoup(doc, 'lxml') 13 | pgrr = html.find('td', class_='pgRR') 14 | s = str(pgrr.a['href']).split('=') 15 | last_page = s[-1] 16 | 17 | df = pd.DataFrame() 18 | sise_url = 'https://finance.naver.com/item/sise_day.nhn?code=068270' 19 | for page in range(1, int(last_page)+1): 20 | page_url = '{}&page={}'.format(sise_url, page) 21 | df = df.append(pd.read_html(page_url, header=0)[0]) 22 | 23 | df = df.dropna() 24 | df = df.iloc[0:30] 25 | df = df.sort_values(by='날짜') 26 | for idx in range(0, len(df)): 27 | dt = datetime.strptime(df['날짜'].values[idx], '%Y.%m.%d').date() 28 | df['날짜'].values[idx] = mdates.date2num(dt) 29 | ohlc = df[['날짜','시가','고가','저가','종가']] 30 | 31 | plt.figure(figsize=(9, 6)) 32 | ax = plt.subplot(1, 1, 1) 33 | plt.title('Celltrion (mpl_finance candle stick)') 34 | candlestick_ohlc(ax, ohlc.values, width=0.7, colorup='red', colordown='blue') 35 | ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d')) 36 | plt.xticks(rotation=45) 37 | plt.grid(color='gray', linestyle='--') 38 | plt.show() 39 | -------------------------------------------------------------------------------- /04_Web_Scraping/ch04_03_Celltrion_CandleChart_NewSchool.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | from urllib.request import urlopen 3 | from bs4 import BeautifulSoup 4 | import mplfinance as mpf 5 | 6 | url = 'https://finance.naver.com/item/sise_day.nhn?code=068270&page=1' 7 | with urlopen(url) as doc: 8 | html = BeautifulSoup(doc, 'lxml') 9 | pgrr = html.find('td', class_='pgRR') 10 | s = str(pgrr.a['href']).split('=') 11 | last_page = s[-1] 12 | 13 | df = pd.DataFrame() 14 | sise_url = 'https://finance.naver.com/item/sise_day.nhn?code=068270' 15 | for page in range(1, int(last_page)+1): 16 | page_url = '{}&page={}'.format(sise_url, page) 17 | df = df.append(pd.read_html(page_url, header=0)[0]) 18 | 19 | df = df.dropna() 20 | df = df.iloc[0:30] 21 | df = df.rename(columns={'날짜':'Date', '시가':'Open', '고가':'High', '저가':'Low', '종가':'Close', '거래량':'Volume'}) 22 | df = df.sort_values(by='Date') 23 | df.index = pd.to_datetime(df.Date) 24 | df = df[['Open', 'High', 'Low', 'Close', 'Volume']] 25 | 26 | mpf.plot(df, title='Celltrion candle chart', type='candle') 27 | 28 | mpf.plot(df, title='Celltrion ohlc chart', type='ohlc') 29 | 30 | kwargs = dict(title='Celltrion customized chart', type='candle', 31 | mav=(2, 4, 6), volume=True, ylabel='ohlc candles') 32 | mc = mpf.make_marketcolors(up='r', down='b', inherit=True) 33 | s = mpf.make_mpf_style(marketcolors=mc) 34 | mpf.plot(df, **kwargs, style=s) 35 | 36 | 37 | -------------------------------------------------------------------------------- /04_Web_Scraping/imgs/CandleChart.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/04_Web_Scraping/imgs/CandleChart.jpg -------------------------------------------------------------------------------- /04_Web_Scraping/imgs/CelltrionURL.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/04_Web_Scraping/imgs/CelltrionURL.jpg -------------------------------------------------------------------------------- /04_Web_Scraping/imgs/Celltrion_CandleChart_NewSchool.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/04_Web_Scraping/imgs/Celltrion_CandleChart_NewSchool.jpg -------------------------------------------------------------------------------- /04_Web_Scraping/imgs/Celltrion_CandleStickChart_OldSchool.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/04_Web_Scraping/imgs/Celltrion_CandleStickChart_OldSchool.jpg -------------------------------------------------------------------------------- /04_Web_Scraping/imgs/Celltrion_CustomizedCandleChart_NewSchool.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/04_Web_Scraping/imgs/Celltrion_CustomizedCandleChart_NewSchool.jpg -------------------------------------------------------------------------------- /04_Web_Scraping/imgs/Celltrion_OhlcChart_NewSchool.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/04_Web_Scraping/imgs/Celltrion_OhlcChart_NewSchool.jpg -------------------------------------------------------------------------------- /04_Web_Scraping/imgs/Celltrion_close.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/04_Web_Scraping/imgs/Celltrion_close.jpg -------------------------------------------------------------------------------- /04_Web_Scraping/imgs/HtmlSample.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/04_Web_Scraping/imgs/HtmlSample.jpg -------------------------------------------------------------------------------- /04_Web_Scraping/imgs/OhlcCandleChart.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/04_Web_Scraping/imgs/OhlcCandleChart.jpg -------------------------------------------------------------------------------- /04_Web_Scraping/imgs/bs4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/04_Web_Scraping/imgs/bs4.jpg -------------------------------------------------------------------------------- /04_Web_Scraping/imgs/kind.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/04_Web_Scraping/imgs/kind.jpg -------------------------------------------------------------------------------- /04_Web_Scraping/imgs/kind_excel.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/04_Web_Scraping/imgs/kind_excel.jpg -------------------------------------------------------------------------------- /04_Web_Scraping/imgs/kind_notepad.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/04_Web_Scraping/imgs/kind_notepad.jpg -------------------------------------------------------------------------------- /04_Web_Scraping/imgs/sise1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/04_Web_Scraping/imgs/sise1.jpg -------------------------------------------------------------------------------- /04_Web_Scraping/imgs/sise2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/04_Web_Scraping/imgs/sise2.jpg -------------------------------------------------------------------------------- /05_Stock_Price_API/Investar/Analyzer.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | import pymysql 3 | from datetime import datetime 4 | from datetime import timedelta 5 | import re 6 | 7 | class MarketDB: 8 | def __init__(self): 9 | """생성자: MariaDB 연결 및 종목코드 딕셔너리 생성""" 10 | self.conn = pymysql.connect(host='localhost', user='root', 11 | password='myPa$$word', db='INVESTAR', charset='utf8') 12 | self.codes = {} 13 | self.get_comp_info() 14 | 15 | def __del__(self): 16 | """소멸자: MariaDB 연결 해제""" 17 | self.conn.close() 18 | 19 | def get_comp_info(self): 20 | """company_info 테이블에서 읽어와서 codes에 저장""" 21 | sql = "SELECT * FROM company_info" 22 | krx = pd.read_sql(sql, self.conn) 23 | for idx in range(len(krx)): 24 | self.codes[krx['code'].values[idx]] = krx['company'].values[idx] 25 | 26 | def get_daily_price(self, code, start_date=None, end_date=None): 27 | """KRX 종목의 일별 시세를 데이터프레임 형태로 반환 28 | - code : KRX 종목코드('005930') 또는 상장기업명('삼성전자') 29 | - start_date : 조회 시작일('2020-01-01'), 미입력 시 1년 전 오늘 30 | - end_date : 조회 종료일('2020-12-31'), 미입력 시 오늘 날짜 31 | """ 32 | if start_date is None: 33 | one_year_ago = datetime.today() - timedelta(days=365) 34 | start_date = one_year_ago.strftime('%Y-%m-%d') 35 | print("start_date is initialized to '{}'".format(start_date)) 36 | else: 37 | start_lst = re.split('\D+', start_date) 38 | if start_lst[0] == '': 39 | start_lst = start_lst[1:] 40 | start_year = int(start_lst[0]) 41 | start_month = int(start_lst[1]) 42 | start_day = int(start_lst[2]) 43 | if start_year < 1900 or start_year > 2200: 44 | print(f"ValueError: start_year({start_year:d}) is wrong.") 45 | return 46 | if start_month < 1 or start_month > 12: 47 | print(f"ValueError: start_month({start_month:d}) is wrong.") 48 | return 49 | if start_day < 1 or start_day > 31: 50 | print(f"ValueError: start_day({start_day:d}) is wrong.") 51 | return 52 | start_date=f"{start_year:04d}-{start_month:02d}-{start_day:02d}" 53 | 54 | if end_date is None: 55 | end_date = datetime.today().strftime('%Y-%m-%d') 56 | print("end_date is initialized to '{}'".format(end_date)) 57 | else: 58 | end_lst = re.split('\D+', end_date) 59 | if end_lst[0] == '': 60 | end_lst = end_lst[1:] 61 | end_year = int(end_lst[0]) 62 | end_month = int(end_lst[1]) 63 | end_day = int(end_lst[2]) 64 | if end_year < 1800 or end_year > 2200: 65 | print(f"ValueError: end_year({end_year:d}) is wrong.") 66 | return 67 | if end_month < 1 or end_month > 12: 68 | print(f"ValueError: end_month({end_month:d}) is wrong.") 69 | return 70 | if end_day < 1 or end_day > 31: 71 | print(f"ValueError: end_day({end_day:d}) is wrong.") 72 | return 73 | end_date = f"{end_year:04d}-{end_month:02d}-{end_day:02d}" 74 | 75 | codes_keys = list(self.codes.keys()) 76 | codes_values = list(self.codes.values()) 77 | 78 | if code in codes_keys: 79 | pass 80 | elif code in codes_values: 81 | idx = codes_values.index(code) 82 | code = codes_keys[idx] 83 | else: 84 | print(f"ValueError: Code({code}) doesn't exist.") 85 | sql = f"SELECT * FROM daily_price WHERE code = '{code}'"\ 86 | f" and date >= '{start_date}' and date <= '{end_date}'" 87 | df = pd.read_sql(sql, self.conn) 88 | df.index = df['date'] 89 | return df 90 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /05_Stock_Price_API/Investar/DBUpdater.py: -------------------------------------------------------------------------------- 1 | 2 | import pandas as pd 3 | from bs4 import BeautifulSoup 4 | import urllib, pymysql, calendar, time, json 5 | from urllib.request import urlopen 6 | from datetime import datetime 7 | from threading import Timer 8 | 9 | class DBUpdater: 10 | def __init__(self): 11 | """생성자: MariaDB 연결 및 종목코드 딕셔너리 생성""" 12 | self.conn = pymysql.connect(host='localhost', user='root', 13 | password='myPa$$word', db='INVESTAR', charset='utf8') 14 | 15 | with self.conn.cursor() as curs: 16 | sql = """ 17 | CREATE TABLE IF NOT EXISTS company_info ( 18 | code VARCHAR(20), 19 | company VARCHAR(40), 20 | last_update DATE, 21 | PRIMARY KEY (code)) 22 | """ 23 | curs.execute(sql) 24 | sql = """ 25 | CREATE TABLE IF NOT EXISTS daily_price ( 26 | code VARCHAR(20), 27 | date DATE, 28 | open BIGINT(20), 29 | high BIGINT(20), 30 | low BIGINT(20), 31 | close BIGINT(20), 32 | diff BIGINT(20), 33 | volume BIGINT(20), 34 | PRIMARY KEY (code, date)) 35 | """ 36 | curs.execute(sql) 37 | self.conn.commit() 38 | self.codes = dict() 39 | 40 | def __del__(self): 41 | """소멸자: MariaDB 연결 해제""" 42 | self.conn.close() 43 | 44 | def read_krx_code(self): 45 | """KRX로부터 상장기업 목록 파일을 읽어와서 데이터프레임으로 반환""" 46 | url = 'http://kind.krx.co.kr/corpgeneral/corpList.do?method='\ 47 | 'download&searchType=13' 48 | krx = pd.read_html(url, header=0)[0] 49 | krx = krx[['종목코드', '회사명']] 50 | krx = krx.rename(columns={'종목코드': 'code', '회사명': 'company'}) 51 | krx.code = krx.code.map('{:06d}'.format) 52 | return krx 53 | 54 | def update_comp_info(self): 55 | """종목코드를 company_info 테이블에 업데이트 한 후 딕셔너리에 저장""" 56 | sql = "SELECT * FROM company_info" 57 | df = pd.read_sql(sql, self.conn) 58 | for idx in range(len(df)): 59 | self.codes[df['code'].values[idx]] = df['company'].values[idx] 60 | 61 | with self.conn.cursor() as curs: 62 | sql = "SELECT max(last_update) FROM company_info" 63 | curs.execute(sql) 64 | rs = curs.fetchone() 65 | today = datetime.today().strftime('%Y-%m-%d') 66 | if rs[0] == None or rs[0].strftime('%Y-%m-%d') < today: 67 | krx = self.read_krx_code() 68 | for idx in range(len(krx)): 69 | code = krx.code.values[idx] 70 | company = krx.company.values[idx] 71 | sql = f"REPLACE INTO company_info (code, company, last"\ 72 | f"_update) VALUES ('{code}', '{company}', '{today}')" 73 | curs.execute(sql) 74 | self.codes[code] = company 75 | tmnow = datetime.now().strftime('%Y-%m-%d %H:%M') 76 | print(f"[{tmnow}] #{idx+1:04d} REPLACE INTO company_info "\ 77 | f"VALUES ({code}, {company}, {today})") 78 | self.conn.commit() 79 | print('') 80 | 81 | def read_naver(self, code, company, pages_to_fetch): 82 | """네이버에서 주식 시세를 읽어서 데이터프레임으로 반환""" 83 | try: 84 | url = f"http://finance.naver.com/item/sise_day.nhn?code={code}" 85 | with urlopen(url) as doc: 86 | if doc is None: 87 | return None 88 | html = BeautifulSoup(doc, "lxml") 89 | pgrr = html.find("td", class_="pgRR") 90 | if pgrr is None: 91 | return None 92 | s = str(pgrr.a["href"]).split('=') 93 | lastpage = s[-1] 94 | df = pd.DataFrame() 95 | pages = min(int(lastpage), pages_to_fetch) 96 | for page in range(1, pages + 1): 97 | pg_url = '{}&page={}'.format(url, page) 98 | df = df.append(pd.read_html(pg_url, header=0)[0]) 99 | tmnow = datetime.now().strftime('%Y-%m-%d %H:%M') 100 | print('[{}] {} ({}) : {:04d}/{:04d} pages are downloading...'. 101 | format(tmnow, company, code, page, pages), end="\r") 102 | df = df.rename(columns={'날짜':'date','종가':'close','전일비':'diff' 103 | ,'시가':'open','고가':'high','저가':'low','거래량':'volume'}) 104 | df['date'] = df['date'].replace('.', '-') 105 | df = df.dropna() 106 | df[['close', 'diff', 'open', 'high', 'low', 'volume']] = df[['close', 107 | 'diff', 'open', 'high', 'low', 'volume']].astype(int) 108 | df = df[['date', 'open', 'high', 'low', 'close', 'diff', 'volume']] 109 | except Exception as e: 110 | print('Exception occured :', str(e)) 111 | return None 112 | return df 113 | 114 | def replace_into_db(self, df, num, code, company): 115 | """네이버에서 읽어온 주식 시세를 DB에 REPLACE""" 116 | with self.conn.cursor() as curs: 117 | for r in df.itertuples(): 118 | sql = f"REPLACE INTO daily_price VALUES ('{code}', "\ 119 | f"'{r.date}', {r.open}, {r.high}, {r.low}, {r.close}, "\ 120 | f"{r.diff}, {r.volume})" 121 | curs.execute(sql) 122 | self.conn.commit() 123 | print('[{}] #{:04d} {} ({}) : {} rows > REPLACE INTO daily_'\ 124 | 'price [OK]'.format(datetime.now().strftime('%Y-%m-%d'\ 125 | ' %H:%M'), num+1, company, code, len(df))) 126 | 127 | def update_daily_price(self, pages_to_fetch): 128 | """KRX 상장법인의 주식 시세를 네이버로부터 읽어서 DB에 업데이트""" 129 | for idx, code in enumerate(self.codes): 130 | df = self.read_naver(code, self.codes[code], pages_to_fetch) 131 | if df is None: 132 | continue 133 | self.replace_into_db(df, idx, code, self.codes[code]) 134 | 135 | def execute_daily(self): 136 | """실행 즉시 및 매일 오후 다섯시에 daily_price 테이블 업데이트""" 137 | self.update_comp_info() 138 | 139 | try: 140 | with open('config.json', 'r') as in_file: 141 | config = json.load(in_file) 142 | pages_to_fetch = config['pages_to_fetch'] 143 | except FileNotFoundError: 144 | with open('config.json', 'w') as out_file: 145 | pages_to_fetch = 100 146 | config = {'pages_to_fetch': 1} 147 | json.dump(config, out_file) 148 | self.update_daily_price(pages_to_fetch) 149 | 150 | tmnow = datetime.now() 151 | lastday = calendar.monthrange(tmnow.year, tmnow.month)[1] 152 | if tmnow.month == 12 and tmnow.day == lastday: 153 | tmnext = tmnow.replace(year=tmnow.year+1, month=1, day=1, 154 | hour=17, minute=0, second=0) 155 | elif tmnow.day == lastday: 156 | tmnext = tmnow.replace(month=tmnow.month+1, day=1, hour=17, 157 | minute=0, second=0) 158 | else: 159 | tmnext = tmnow.replace(day=tmnow.day+1, hour=17, minute=0, 160 | second=0) 161 | tmdiff = tmnext - tmnow 162 | secs = tmdiff.seconds 163 | t = Timer(secs, self.execute_daily) 164 | print("Waiting for next update ({}) ... ".format(tmnext.strftime 165 | ('%Y-%m-%d %H:%M'))) 166 | t.start() 167 | 168 | if __name__ == '__main__': 169 | dbu = DBUpdater() 170 | dbu.execute_daily() 171 | -------------------------------------------------------------------------------- /05_Stock_Price_API/Investar/DBUpdaterEx.py: -------------------------------------------------------------------------------- 1 | 2 | import pandas as pd 3 | from bs4 import BeautifulSoup 4 | import pymysql, calendar, time, json 5 | import requests 6 | from datetime import datetime 7 | from threading import Timer 8 | 9 | class DBUpdater: 10 | def __init__(self): 11 | """생성자: MariaDB 연결 및 종목코드 딕셔너리 생성""" 12 | self.conn = pymysql.connect(host='localhost', user='root', 13 | password='myPa$$word', db='INVESTAR', charset='utf8') 14 | 15 | with self.conn.cursor() as curs: 16 | sql = """ 17 | CREATE TABLE IF NOT EXISTS company_info ( 18 | code VARCHAR(20), 19 | company VARCHAR(40), 20 | last_update DATE, 21 | PRIMARY KEY (code)) 22 | """ 23 | curs.execute(sql) 24 | sql = """ 25 | CREATE TABLE IF NOT EXISTS daily_price ( 26 | code VARCHAR(20), 27 | date DATE, 28 | open BIGINT(20), 29 | high BIGINT(20), 30 | low BIGINT(20), 31 | close BIGINT(20), 32 | diff BIGINT(20), 33 | volume BIGINT(20), 34 | PRIMARY KEY (code, date)) 35 | """ 36 | curs.execute(sql) 37 | self.conn.commit() 38 | self.codes = dict() 39 | 40 | def __del__(self): 41 | """소멸자: MariaDB 연결 해제""" 42 | self.conn.close() 43 | 44 | def read_krx_code(self): 45 | """KRX로부터 상장기업 목록 파일을 읽어와서 데이터프레임으로 반환""" 46 | url = 'http://kind.krx.co.kr/corpgeneral/corpList.do?method='\ 47 | 'download&searchType=13' 48 | krx = pd.read_html(url, header=0)[0] 49 | krx = krx[['종목코드', '회사명']] 50 | krx = krx.rename(columns={'종목코드': 'code', '회사명': 'company'}) 51 | krx.code = krx.code.map('{:06d}'.format) 52 | return krx 53 | 54 | def update_comp_info(self): 55 | """종목코드를 company_info 테이블에 업데이트 한 후 딕셔너리에 저장""" 56 | sql = "SELECT * FROM company_info" 57 | df = pd.read_sql(sql, self.conn) 58 | for idx in range(len(df)): 59 | self.codes[df['code'].values[idx]] = df['company'].values[idx] 60 | 61 | with self.conn.cursor() as curs: 62 | sql = "SELECT max(last_update) FROM company_info" 63 | curs.execute(sql) 64 | rs = curs.fetchone() 65 | today = datetime.today().strftime('%Y-%m-%d') 66 | if rs[0] == None or rs[0].strftime('%Y-%m-%d') < today: 67 | krx = self.read_krx_code() 68 | for idx in range(len(krx)): 69 | code = krx.code.values[idx] 70 | company = krx.company.values[idx] 71 | sql = f"REPLACE INTO company_info (code, company, last"\ 72 | f"_update) VALUES ('{code}', '{company}', '{today}')" 73 | curs.execute(sql) 74 | self.codes[code] = company 75 | tmnow = datetime.now().strftime('%Y-%m-%d %H:%M') 76 | print(f"[{tmnow}] #{idx+1:04d} REPLACE INTO company_info "\ 77 | f"VALUES ({code}, {company}, {today})") 78 | self.conn.commit() 79 | print('') 80 | 81 | def read_naver(self, code, company, pages_to_fetch): 82 | """네이버에서 주식 시세를 읽어서 데이터프레임으로 반환""" 83 | try: 84 | url = f"http://finance.naver.com/item/sise_day.nhn?code={code}" 85 | html = BeautifulSoup(requests.get(url, 86 | headers={'User-agent': 'Mozilla/5.0'}).text, "lxml") 87 | pgrr = html.find("td", class_="pgRR") 88 | if pgrr is None: 89 | return None 90 | s = str(pgrr.a["href"]).split('=') 91 | lastpage = s[-1] 92 | df = pd.DataFrame() 93 | pages = min(int(lastpage), pages_to_fetch) 94 | for page in range(1, pages + 1): 95 | pg_url = '{}&page={}'.format(url, page) 96 | df = df.append(pd.read_html(requests.get(pg_url, 97 | headers={'User-agent': 'Mozilla/5.0'}).text)[0]) 98 | tmnow = datetime.now().strftime('%Y-%m-%d %H:%M') 99 | print('[{}] {} ({}) : {:04d}/{:04d} pages are downloading...'. 100 | format(tmnow, company, code, page, pages), end="\r") 101 | df = df.rename(columns={'날짜':'date','종가':'close','전일비':'diff' 102 | ,'시가':'open','고가':'high','저가':'low','거래량':'volume'}) 103 | df['date'] = df['date'].replace('.', '-') 104 | df['diff'] = df['diff'].str.extract(r'(\d+)') 105 | df = df.dropna() 106 | df[['close', 'diff', 'open', 'high', 'low', 'volume']] = df[['close', 107 | 'diff', 'open', 'high', 'low', 'volume']].astype(int) 108 | df = df[['date', 'open', 'high', 'low', 'close', 'diff', 'volume']] 109 | except Exception as e: 110 | print('Exception occured :', str(e)) 111 | return None 112 | return df 113 | 114 | def replace_into_db(self, df, num, code, company): 115 | """네이버에서 읽어온 주식 시세를 DB에 REPLACE""" 116 | with self.conn.cursor() as curs: 117 | for r in df.itertuples(): 118 | sql = f"REPLACE INTO daily_price VALUES ('{code}', "\ 119 | f"'{r.date}', {r.open}, {r.high}, {r.low}, {r.close}, "\ 120 | f"{r.diff}, {r.volume})" 121 | curs.execute(sql) 122 | self.conn.commit() 123 | print('[{}] #{:04d} {} ({}) : {} rows > REPLACE INTO daily_'\ 124 | 'price [OK]'.format(datetime.now().strftime('%Y-%m-%d'\ 125 | ' %H:%M'), num+1, company, code, len(df))) 126 | 127 | def update_daily_price(self, pages_to_fetch): 128 | """KRX 상장법인의 주식 시세를 네이버로부터 읽어서 DB에 업데이트""" 129 | for idx, code in enumerate(self.codes): 130 | df = self.read_naver(code, self.codes[code], pages_to_fetch) 131 | if df is None: 132 | continue 133 | self.replace_into_db(df, idx, code, self.codes[code]) 134 | 135 | def execute_daily(self): 136 | """실행 즉시 및 매일 오후 다섯시에 daily_price 테이블 업데이트""" 137 | self.update_comp_info() 138 | 139 | try: 140 | with open('config.json', 'r') as in_file: 141 | config = json.load(in_file) 142 | pages_to_fetch = config['pages_to_fetch'] 143 | except FileNotFoundError: 144 | with open('config.json', 'w') as out_file: 145 | pages_to_fetch = 100 146 | config = {'pages_to_fetch': 1} 147 | json.dump(config, out_file) 148 | self.update_daily_price(pages_to_fetch) 149 | 150 | tmnow = datetime.now() 151 | lastday = calendar.monthrange(tmnow.year, tmnow.month)[1] 152 | if tmnow.month == 12 and tmnow.day == lastday: 153 | tmnext = tmnow.replace(year=tmnow.year+1, month=1, day=1, 154 | hour=17, minute=0, second=0) 155 | elif tmnow.day == lastday: 156 | tmnext = tmnow.replace(month=tmnow.month+1, day=1, hour=17, 157 | minute=0, second=0) 158 | else: 159 | tmnext = tmnow.replace(day=tmnow.day+1, hour=17, minute=0, 160 | second=0) 161 | tmdiff = tmnext - tmnow 162 | secs = tmdiff.seconds 163 | t = Timer(secs, self.execute_daily) 164 | print("Waiting for next update ({}) ... ".format(tmnext.strftime 165 | ('%Y-%m-%d %H:%M'))) 166 | t.start() 167 | 168 | if __name__ == '__main__': 169 | dbu = DBUpdater() 170 | dbu.execute_daily() 171 | -------------------------------------------------------------------------------- /05_Stock_Price_API/Investar/MarketDB.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | #from bs4 import BeautifulSoup 3 | #import urllib 4 | #from urllib.request import urlopen 5 | import pymysql 6 | #import time 7 | #import pandas.io.sql as sql 8 | from datetime import datetime 9 | #from threading import Timer 10 | #import matplotlib.pyplot as plt 11 | 12 | class MarketDB: 13 | def __init__(self): 14 | """생성자: MariaDB 연결 및 종목코드 딕셔너리 생성""" 15 | self.conn = pymysql.connect(host='localhost', user='root', password='myPa$$word', db='INVESTAR', charset='utf8') 16 | self.codes = dict() 17 | self.getCompanyInfo() 18 | 19 | def __del__(self): 20 | """소멸자: MariaDB 연결 해제""" 21 | self.conn.close() 22 | 23 | def getCompanyInfo(self): 24 | """company_info 테이블에서 읽어와서 companyData와 codes에 저장""" 25 | sql = "SELECT * FROM company_info" 26 | companyInfo = pd.read_sql(sql, self.conn) 27 | for idx in range(len(companyInfo)): 28 | self.codes[companyInfo['code'].values[idx]] = companyInfo['company'].values[idx] 29 | 30 | def getDailyPrice(self, code, startDate, endDate): 31 | """daily_price 테이블에서 읽어와서 데이터프레임으로 반환""" 32 | sql = "SELECT * FROM daily_price WHERE code = '{}' and date >= '{}' and date <= '{}'".format(code, startDate, endDate) 33 | df = pd.read_sql(sql, self.conn) 34 | df.index = df['date'] 35 | return df 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /05_Stock_Price_API/ch05_01_YahooFinance_SEC.py: -------------------------------------------------------------------------------- 1 | from pandas_datareader import data as pdr 2 | import yfinance as yf 3 | yf.pdr_override() 4 | import matplotlib.pyplot as plt 5 | 6 | df = pdr.get_data_yahoo('005930.KS', '2017-01-01') # ① 7 | 8 | plt.figure(figsize=(9, 6)) 9 | plt.subplot(2, 1, 1) # ② 10 | plt.title('Samsung Electronics (Yahoo Finance)') 11 | plt.plot(df.index, df['Close'], 'c', label='Close') # ③ 12 | plt.plot(df.index, df['Adj Close'], 'b--', label='Adj Close') # ④ 13 | plt.legend(loc='best') 14 | plt.subplot(2, 1, 2) # ⑤ 15 | plt.bar(df.index, df['Volume'], color='g', label='Volume') # ⑥ 16 | plt.legend(loc='best') 17 | plt.show() 18 | -------------------------------------------------------------------------------- /05_Stock_Price_API/ch05_02_NaverDatabase_SEC.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | from Investar import Analyzer # ① 3 | 4 | mk = Analyzer.MarketDB() # ② 5 | df = mk.get_daily_price('005930', '2017-07-10', '2018-06-30') # ③ 6 | 7 | plt.figure(figsize=(9, 6)) 8 | plt.subplot(2, 1, 1) 9 | plt.title('Samsung Electronics (Investar Data)') 10 | plt.plot(df.index, df['close'], 'c', label='Close') # ④ 11 | plt.legend(loc='best') 12 | plt.subplot(2, 1, 2) 13 | plt.bar(df.index, df['volume'], color='g', label='Volume') 14 | plt.legend(loc='best') 15 | plt.show() -------------------------------------------------------------------------------- /05_Stock_Price_API/ch05_03_SelectVersion.py: -------------------------------------------------------------------------------- 1 | import pymysql 2 | 3 | connection = pymysql.connect(host='localhost', port=3306, db='INVESTAR', 4 | user='root', passwd='myPa$$word', autocommit=True) 5 | 6 | cursor = connection.cursor() 7 | cursor.execute("SELECT VERSION();") 8 | result = cursor.fetchone() 9 | 10 | print ("MariaDB version : {}".format(result)) 11 | 12 | connection.close() -------------------------------------------------------------------------------- /05_Stock_Price_API/ch05_04_CreateTable.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS company_info ( 2 | code VARCHAR(20), 3 | company VARCHAR(40), 4 | last_update DATE, 5 | PRIMARY KEY (code) 6 | ); 7 | 8 | CREATE TABLE IF NOT EXISTS daily_price ( 9 | code VARCHAR(20), 10 | date DATE, 11 | open BIGINT(20), 12 | high BIGINT(20), 13 | low BIGINT(20), 14 | close BIGINT(20), 15 | diff BIGINT(20), 16 | volume BIGINT(20), 17 | PRIMARY KEY (code, date) 18 | ); 19 | -------------------------------------------------------------------------------- /05_Stock_Price_API/imgs/API_Client1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/05_Stock_Price_API/imgs/API_Client1.jpg -------------------------------------------------------------------------------- /05_Stock_Price_API/imgs/API_Client2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/05_Stock_Price_API/imgs/API_Client2.jpg -------------------------------------------------------------------------------- /05_Stock_Price_API/imgs/API_ConfigJson.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/05_Stock_Price_API/imgs/API_ConfigJson.jpg -------------------------------------------------------------------------------- /05_Stock_Price_API/imgs/API_ConfigMy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/05_Stock_Price_API/imgs/API_ConfigMy.jpg -------------------------------------------------------------------------------- /05_Stock_Price_API/imgs/API_DBUpdater.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/05_Stock_Price_API/imgs/API_DBUpdater.jpg -------------------------------------------------------------------------------- /05_Stock_Price_API/imgs/API_DBUpdater1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/05_Stock_Price_API/imgs/API_DBUpdater1.jpg -------------------------------------------------------------------------------- /05_Stock_Price_API/imgs/API_DBUpdater2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/05_Stock_Price_API/imgs/API_DBUpdater2.jpg -------------------------------------------------------------------------------- /05_Stock_Price_API/imgs/API_Download2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/05_Stock_Price_API/imgs/API_Download2.jpg -------------------------------------------------------------------------------- /05_Stock_Price_API/imgs/API_GetDailyPrice.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/05_Stock_Price_API/imgs/API_GetDailyPrice.jpg -------------------------------------------------------------------------------- /05_Stock_Price_API/imgs/API_HeidiSQL1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/05_Stock_Price_API/imgs/API_HeidiSQL1.jpg -------------------------------------------------------------------------------- /05_Stock_Price_API/imgs/API_HeidiSQL2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/05_Stock_Price_API/imgs/API_HeidiSQL2.jpg -------------------------------------------------------------------------------- /05_Stock_Price_API/imgs/API_HeidiSQL3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/05_Stock_Price_API/imgs/API_HeidiSQL3.jpg -------------------------------------------------------------------------------- /05_Stock_Price_API/imgs/API_HeidiSQL4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/05_Stock_Price_API/imgs/API_HeidiSQL4.jpg -------------------------------------------------------------------------------- /05_Stock_Price_API/imgs/API_HeidiSQL5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/05_Stock_Price_API/imgs/API_HeidiSQL5.jpg -------------------------------------------------------------------------------- /05_Stock_Price_API/imgs/API_Installer.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/05_Stock_Price_API/imgs/API_Installer.jpg -------------------------------------------------------------------------------- /05_Stock_Price_API/imgs/API_Installer2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/05_Stock_Price_API/imgs/API_Installer2.jpg -------------------------------------------------------------------------------- /05_Stock_Price_API/imgs/API_Installer3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/05_Stock_Price_API/imgs/API_Installer3.jpg -------------------------------------------------------------------------------- /05_Stock_Price_API/imgs/API_RunRegistry.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/05_Stock_Price_API/imgs/API_RunRegistry.jpg -------------------------------------------------------------------------------- /05_Stock_Price_API/imgs/DBUpdaterEx.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/05_Stock_Price_API/imgs/DBUpdaterEx.jpg -------------------------------------------------------------------------------- /05_Stock_Price_API/imgs/DBUpdaterEx2024-03-03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/05_Stock_Price_API/imgs/DBUpdaterEx2024-03-03.png -------------------------------------------------------------------------------- /05_Stock_Price_API/imgs/DBUpdaterEx_2024-06-30.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/05_Stock_Price_API/imgs/DBUpdaterEx_2024-06-30.jpg -------------------------------------------------------------------------------- /05_Stock_Price_API/imgs/ExceptionOccured_2024-06-30.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/05_Stock_Price_API/imgs/ExceptionOccured_2024-06-30.jpg -------------------------------------------------------------------------------- /05_Stock_Price_API/imgs/GetDailyPrice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/05_Stock_Price_API/imgs/GetDailyPrice.png -------------------------------------------------------------------------------- /05_Stock_Price_API/imgs/HeidiSQL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/05_Stock_Price_API/imgs/HeidiSQL.png -------------------------------------------------------------------------------- /05_Stock_Price_API/imgs/MTV2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/05_Stock_Price_API/imgs/MTV2.png -------------------------------------------------------------------------------- /05_Stock_Price_API/imgs/MariaDB_Download.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/05_Stock_Price_API/imgs/MariaDB_Download.jpg -------------------------------------------------------------------------------- /05_Stock_Price_API/imgs/MariaDB_DownloadPage.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/05_Stock_Price_API/imgs/MariaDB_DownloadPage.jpg -------------------------------------------------------------------------------- /05_Stock_Price_API/imgs/MariaDB_IndexPage.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/05_Stock_Price_API/imgs/MariaDB_IndexPage.jpg -------------------------------------------------------------------------------- /06_Trading_Strategy/ch06_01_EfficientFrontier.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pandas as pd 3 | import matplotlib.pyplot as plt 4 | from Investar import Analyzer 5 | 6 | mk = Analyzer.MarketDB() 7 | stocks = ['삼성전자', 'SK하이닉스', '현대자동차', 'NAVER'] 8 | df = pd.DataFrame() 9 | for s in stocks: 10 | df[s] = mk.get_daily_price(s, '2016-01-04', '2018-04-27')['close'] 11 | 12 | daily_ret = df.pct_change() 13 | annual_ret = daily_ret.mean() * 252 14 | daily_cov = daily_ret.cov() 15 | annual_cov = daily_cov * 252 16 | 17 | port_ret = [] 18 | port_risk = [] 19 | port_weights = [] 20 | 21 | for _ in range(20000): 22 | weights = np.random.random(len(stocks)) 23 | weights /= np.sum(weights) 24 | 25 | returns = np.dot(weights, annual_ret) 26 | risk = np.sqrt(np.dot(weights.T, np.dot(annual_cov, weights))) 27 | 28 | port_ret.append(returns) 29 | port_risk.append(risk) 30 | port_weights.append(weights) 31 | 32 | portfolio = {'Returns': port_ret, 'Risk': port_risk} 33 | for i, s in enumerate(stocks): 34 | portfolio[s] = [weight[i] for weight in port_weights] 35 | df = pd.DataFrame(portfolio) 36 | df = df[['Returns', 'Risk'] + [s for s in stocks]] 37 | 38 | df.plot.scatter(x='Risk', y='Returns', figsize=(8, 6), grid=True) 39 | plt.title('Efficient Frontier') 40 | plt.xlabel('Risk') 41 | plt.ylabel('Expected Returns') 42 | plt.show() -------------------------------------------------------------------------------- /06_Trading_Strategy/ch06_02_PortfolioOptimization.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pandas as pd 3 | import matplotlib.pyplot as plt 4 | from Investar import Analyzer 5 | 6 | mk = Analyzer.MarketDB() 7 | stocks = ['삼성전자', 'SK하이닉스', '현대자동차', 'NAVER'] 8 | df = pd.DataFrame() 9 | for s in stocks: 10 | df[s] = mk.get_daily_price(s, '2016-01-04', '2018-04-27')['close'] 11 | 12 | daily_ret = df.pct_change() 13 | annual_ret = daily_ret.mean() * 252 14 | daily_cov = daily_ret.cov() 15 | annual_cov = daily_cov * 252 16 | 17 | port_ret = [] 18 | port_risk = [] 19 | port_weights = [] 20 | sharpe_ratio = [] 21 | 22 | for _ in range(20000): 23 | weights = np.random.random(len(stocks)) 24 | weights /= np.sum(weights) 25 | 26 | returns = np.dot(weights, annual_ret) 27 | risk = np.sqrt(np.dot(weights.T, np.dot(annual_cov, weights))) 28 | 29 | port_ret.append(returns) 30 | port_risk.append(risk) 31 | port_weights.append(weights) 32 | sharpe_ratio.append(returns/risk) # ① 33 | 34 | portfolio = {'Returns': port_ret, 'Risk': port_risk, 'Sharpe': sharpe_ratio} 35 | for i, s in enumerate(stocks): 36 | portfolio[s] = [weight[i] for weight in port_weights] 37 | df = pd.DataFrame(portfolio) 38 | df = df[['Returns', 'Risk', 'Sharpe'] + [s for s in stocks]] # ② 39 | 40 | max_sharpe = df.loc[df['Sharpe'] == df['Sharpe'].max()] # ③ 41 | min_risk = df.loc[df['Risk'] == df['Risk'].min()] # ④ 42 | 43 | df.plot.scatter(x='Risk', y='Returns', c='Sharpe', cmap='viridis', 44 | edgecolors='k', figsize=(11,7), grid=True) # ⑤ 45 | plt.scatter(x=max_sharpe['Risk'], y=max_sharpe['Returns'], c='r', 46 | marker='*', s=300) # ⑥ 47 | plt.scatter(x=min_risk['Risk'], y=min_risk['Returns'], c='r', 48 | marker='X', s=200) # ⑦ 49 | plt.title('Portfolio Optimization') 50 | plt.xlabel('Risk') 51 | plt.ylabel('Expected Returns') 52 | plt.show() -------------------------------------------------------------------------------- /06_Trading_Strategy/ch06_03_BollingerBand.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | from Investar import Analyzer 3 | 4 | mk = Analyzer.MarketDB() 5 | df = mk.get_daily_price('NAVER', '2019-01-02') 6 | 7 | df['MA20'] = df['close'].rolling(window=20).mean() # ① 8 | df['stddev'] = df['close'].rolling(window=20).std() # ② 9 | df['upper'] = df['MA20'] + (df['stddev'] * 2) # ③ 10 | df['lower'] = df['MA20'] - (df['stddev'] * 2) # ④ 11 | df = df[19:] # ⑤ 12 | 13 | plt.figure(figsize=(9, 5)) 14 | plt.plot(df.index, df['close'], color='#0000ff', label='Close') # ⑥ 15 | plt.plot(df.index, df['upper'], 'r--', label = 'Upper band') # ⑦ 16 | plt.plot(df.index, df['MA20'], 'k--', label='Moving average 20') 17 | plt.plot(df.index, df['lower'], 'c--', label = 'Lower band') 18 | plt.fill_between(df.index, df['upper'], df['lower'], color='0.9') # ⑧ 19 | plt.legend(loc='best') 20 | plt.title('NAVER Bollinger Band (20 day, 2 std)') 21 | plt.show() 22 | -------------------------------------------------------------------------------- /06_Trading_Strategy/ch06_04_BollingerBand_PercentB.py: -------------------------------------------------------------------------------- 1 | 2 | import matplotlib.pyplot as plt 3 | from Investar import Analyzer 4 | 5 | mk = Analyzer.MarketDB() 6 | df = mk.get_daily_price('NAVER', '2019-01-02') 7 | 8 | df['MA20'] = df['close'].rolling(window=20).mean() 9 | df['stddev'] = df['close'].rolling(window=20).std() 10 | df['upper'] = df['MA20'] + (df['stddev'] * 2) 11 | df['lower'] = df['MA20'] - (df['stddev'] * 2) 12 | df['PB'] = (df['close'] - df['lower']) / (df['upper'] - df['lower']) # ① 13 | df = df[19:] 14 | 15 | plt.figure(figsize=(9, 8)) 16 | plt.subplot(2, 1, 1) # ② 17 | plt.plot(df.index, df['close'], color='#0000ff', label='Close') 18 | plt.plot(df.index, df['upper'], 'r--', label = 'Upper band') 19 | plt.plot(df.index, df['MA20'], 'k--', label='Moving average 20') 20 | plt.plot(df.index, df['lower'], 'c--', label = 'Lower band') 21 | plt.fill_between(df.index, df['upper'], df['lower'], color='0.9') 22 | plt.title('NAVER Bollinger Band(20 day, 2 std)') 23 | plt.legend(loc='best') 24 | 25 | plt.subplot(2, 1, 2) # ③ 26 | plt.plot(df.index, df['PB'], color='b', label='%B') # ④ 27 | plt.grid(True) 28 | plt.legend(loc='best') 29 | plt.show() 30 | -------------------------------------------------------------------------------- /06_Trading_Strategy/ch06_05_BollingerBand_BandWidth.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | from Investar import Analyzer 3 | 4 | mk = Analyzer.MarketDB() 5 | df = mk.get_daily_price('NAVER', '2019-01-02') 6 | df['MA20'] = df['close'].rolling(window=20).mean() 7 | df['stddev'] = df['close'].rolling(window=20).std() 8 | df['upper'] = df['MA20'] + (df['stddev'] * 2) 9 | df['lower'] = df['MA20'] - (df['stddev'] * 2) 10 | df['bandwidth'] = (df['upper'] - df['lower']) / df['MA20'] * 100 # ① 11 | df = df[19:] 12 | 13 | plt.figure(figsize=(9, 8)) 14 | plt.subplot(2, 1, 1) 15 | plt.plot(df.index, df['close'], color='#0000ff', label='Close') 16 | plt.plot(df.index, df['upper'], 'r--', label ='Upper band') 17 | plt.plot(df.index, df['MA20'], 'k--', label='Moving average 20') 18 | plt.plot(df.index, df['lower'], 'c--', label ='Lower band') 19 | plt.fill_between(df.index, df['upper'], df['lower'], color='0.9') 20 | plt.title('NAVER Bollinger Band(20 day, 2 std)') 21 | plt.legend(loc='best') 22 | plt.subplot(2, 1, 2) 23 | plt.plot(df.index, df['bandwidth'], color='m', label='BandWidth') # ② 24 | plt.grid(True) 25 | plt.legend(loc='best') 26 | plt.show() 27 | -------------------------------------------------------------------------------- /06_Trading_Strategy/ch06_06_BollingerBand_TrendFollowing.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | from Investar import Analyzer 3 | 4 | mk = Analyzer.MarketDB() 5 | df = mk.get_daily_price('NAVER', '2019-01-02') 6 | 7 | df['MA20'] = df['close'].rolling(window=20).mean() 8 | df['stddev'] = df['close'].rolling(window=20).std() 9 | df['upper'] = df['MA20'] + (df['stddev'] * 2) 10 | df['lower'] = df['MA20'] - (df['stddev'] * 2) 11 | df['PB'] = (df['close'] - df['lower']) / (df['upper'] - df['lower']) 12 | df['TP'] = (df['high'] + df['low'] + df['close']) / 3 13 | df['PMF'] = 0 14 | df['NMF'] = 0 15 | for i in range(len(df.close)-1): 16 | if df.TP.values[i] < df.TP.values[i+1]: 17 | df.PMF.values[i+1] = df.TP.values[i+1] * df.volume.values[i+1] 18 | df.NMF.values[i+1] = 0 19 | else: 20 | df.NMF.values[i+1] = df.TP.values[i+1] * df.volume.values[i+1] 21 | df.PMF.values[i+1] = 0 22 | df['MFR'] = (df.PMF.rolling(window=10).sum() / 23 | df.NMF.rolling(window=10).sum()) 24 | df['MFI10'] = 100 - 100 / (1 + df['MFR']) 25 | df = df[19:] 26 | 27 | plt.figure(figsize=(9, 8)) 28 | plt.subplot(2, 1, 1) 29 | plt.title('NAVER Bollinger Band(20 day, 2 std) - Trend Following') 30 | plt.plot(df.index, df['close'], color='#0000ff', label='Close') 31 | plt.plot(df.index, df['upper'], 'r--', label ='Upper band') 32 | plt.plot(df.index, df['MA20'], 'k--', label='Moving average 20') 33 | plt.plot(df.index, df['lower'], 'c--', label ='Lower band') 34 | plt.fill_between(df.index, df['upper'], df['lower'], color='0.9') 35 | for i in range(len(df.close)): 36 | if df.PB.values[i] > 0.8 and df.MFI10.values[i] > 80: # ① 37 | plt.plot(df.index.values[i], df.close.values[i], 'r^') # ② 38 | elif df.PB.values[i] < 0.2 and df.MFI10.values[i] < 20: # ③ 39 | plt.plot(df.index.values[i], df.close.values[i], 'bv') # ④ 40 | plt.legend(loc='best') 41 | 42 | plt.subplot(2, 1, 2) 43 | plt.plot(df.index, df['PB'] * 100, 'b', label='%B x 100') # ⑤ 44 | plt.plot(df.index, df['MFI10'], 'g--', label='MFI(10 day)') # ⑥ 45 | plt.yticks([-20, 0, 20, 40, 60, 80, 100, 120]) # ⑦ 46 | for i in range(len(df.close)): 47 | if df.PB.values[i] > 0.8 and df.MFI10.values[i] > 80: 48 | plt.plot(df.index.values[i], 0, 'r^') 49 | elif df.PB.values[i] < 0.2 and df.MFI10.values[i] < 20: 50 | plt.plot(df.index.values[i], 0, 'bv') 51 | plt.grid(True) 52 | plt.legend(loc='best') 53 | plt.show(); 54 | -------------------------------------------------------------------------------- /06_Trading_Strategy/ch06_07_BollingerBand_IIP21.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | from Investar import Analyzer 3 | 4 | mk = Analyzer.MarketDB() 5 | df = mk.get_daily_price('SK하이닉스', '2018-11-01') 6 | 7 | df['MA20'] = df['close'].rolling(window=20).mean() 8 | df['stddev'] = df['close'].rolling(window=20).std() 9 | df['upper'] = df['MA20'] + (df['stddev'] * 2) 10 | df['lower'] = df['MA20'] - (df['stddev'] * 2) 11 | df['PB'] = (df['close'] - df['lower']) / (df['upper'] - df['lower']) 12 | 13 | df['II'] = (2*df['close']-df['high']-df['low']) 14 | /(df['high']-df['low'])*df['volume'] # ① 15 | df['IIP21'] = df['II'].rolling(window=21).sum() 16 | /df['volume'].rolling(window=21).sum()*100 # ② 17 | df = df.dropna() 18 | 19 | plt.figure(figsize=(9, 9)) 20 | plt.subplot(3, 1, 1) 21 | plt.title('SK Hynix Bollinger Band(20 day, 2 std) - Reversals') 22 | plt.plot(df.index, df['close'], 'b', label='Close') 23 | plt.plot(df.index, df['upper'], 'r--', label ='Upper band') 24 | plt.plot(df.index, df['MA20'], 'k--', label='Moving average 20') 25 | plt.plot(df.index, df['lower'], 'c--', label ='Lower band') 26 | plt.fill_between(df.index, df['upper'], df['lower'], color='0.9') 27 | 28 | plt.legend(loc='best') 29 | plt.subplot(3, 1, 2) 30 | plt.plot(df.index, df['PB'], 'b', label='%b') 31 | plt.grid(True) 32 | plt.legend(loc='best') 33 | 34 | plt.subplot(3, 1, 3) # ③ 35 | plt.bar(df.index, df['IIP21'], color='g', label='II% 21day') # ④ 36 | plt.grid(True) 37 | plt.legend(loc='best') 38 | plt.show() -------------------------------------------------------------------------------- /06_Trading_Strategy/ch06_08_BollingerBand_Reversals.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | from Investar import Analyzer 3 | 4 | mk = Analyzer.MarketDB() 5 | df = mk.get_daily_price('SK하이닉스', '2018-11-01') 6 | 7 | df['MA20'] = df['close'].rolling(window=20).mean() 8 | df['stddev'] = df['close'].rolling(window=20).std() 9 | df['upper'] = df['MA20'] + (df['stddev'] * 2) 10 | df['lower'] = df['MA20'] - (df['stddev'] * 2) 11 | df['PB'] = (df['close'] - df['lower']) / (df['upper'] - df['lower']) 12 | 13 | df['II'] = (2*df['close']-df['high']-df['low'])/(df['high']-df['low'])*df['volume'] 14 | df['IIP21'] = df['II'].rolling(window=21).sum()/df['volume'].rolling(window=21).sum()*100 15 | df = df.dropna() 16 | 17 | plt.figure(figsize=(9, 9)) 18 | plt.subplot(3, 1, 1) 19 | plt.title('SK Hynix Bollinger Band(20 day, 2 std) - Reversals') 20 | plt.plot(df.index, df['close'], 'm', label='Close') 21 | plt.plot(df.index, df['upper'], 'r--', label ='Upper band') 22 | plt.plot(df.index, df['MA20'], 'k--', label='Moving average 20') 23 | plt.plot(df.index, df['lower'], 'c--', label ='Lower band') 24 | plt.fill_between(df.index, df['upper'], df['lower'], color='0.9') 25 | for i in range(0, len(df.close)): 26 | if df.PB.values[i] < 0.05 and df.IIP21.values[i] > 0: # ① 27 | plt.plot(df.index.values[i], df.close.values[i], 'r^') # ② 28 | elif df.PB.values[i] > 0.95 and df.IIP21.values[i] < 0: # ③ 29 | plt.plot(df.index.values[i], df.close.values[i], 'bv') # ④ 30 | plt.legend(loc='best') 31 | 32 | plt.subplot(3, 1, 2) 33 | plt.plot(df.index, df['PB'], 'b', label='%b') 34 | plt.grid(True) 35 | plt.legend(loc='best') 36 | 37 | plt.subplot(3, 1, 3) 38 | plt.bar(df.index, df['IIP21'], color='g', label='II% 21day') 39 | for i in range(0, len(df.close)): 40 | if df.PB.values[i] < 0.05 and df.IIP21.values[i] > 0: 41 | plt.plot(df.index.values[i], 0, 'r^') # ⑤ 42 | elif df.PB.values[i] > 0.95 and df.IIP21.values[i] < 0: 43 | plt.plot(df.index.values[i], 0, 'bv') # ⑥ 44 | plt.grid(True) 45 | plt.legend(loc='best') 46 | plt.show() 47 | 48 | 49 | -------------------------------------------------------------------------------- /06_Trading_Strategy/ch06_09_FirstScreen.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | import matplotlib.pyplot as plt 3 | import datetime 4 | from mpl_finance import candlestick_ohlc 5 | #from mplfinance.original_flavor import candlestick_ohlc 6 | import matplotlib.dates as mdates 7 | from Investar import Analyzer 8 | 9 | mk = Analyzer.MarketDB() 10 | df = mk.get_daily_price('엔씨소프트', '2017-01-01') 11 | 12 | 13 | ema60 = df.close.ewm(span=60).mean() # ① 종가의 12주 지수 이동평균 14 | ema130 = df.close.ewm(span=130).mean() # ② 종가의 12주 지수 이동평균 15 | macd = ema60 - ema130 # ③ MACD선 16 | signal = macd.ewm(span=45).mean() # ④ 신호선(MACD의 9주 지수 이동평균) 17 | macdhist = macd - signal # ⑤ MACD 히스토그램 18 | 19 | df = df.assign(ema130=ema130, ema60=ema60, macd=macd, signal=signal, 20 | macdhist=macdhist).dropna() 21 | df['number'] = df.index.map(mdates.date2num) # ⑥ 22 | ohlc = df[['number','open','high','low','close']] 23 | 24 | plt.figure(figsize=(9, 7)) 25 | p1 = plt.subplot(2, 1, 1) 26 | plt.title('Triple Screen Trading - First Screen (NCSOFT)') 27 | plt.grid(True) 28 | candlestick_ohlc(p1, ohlc.values, width=.6, colorup='red', 29 | colordown='blue') # ⑦ 30 | p1.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m')) 31 | plt.plot(df.number, df['ema130'], color='c', label='EMA130') 32 | plt.legend(loc='best') 33 | 34 | p2 = plt.subplot(2, 1, 2) 35 | plt.grid(True) 36 | p2.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m')) 37 | plt.bar(df.number, df['macdhist'], color='m', label='MACD-Hist') 38 | plt.plot(df.number, df['macd'], color='b', label='MACD') 39 | plt.plot(df.number, df['signal'], 'g--', label='MACD-Signal') 40 | plt.legend(loc='best') 41 | plt.show() 42 | -------------------------------------------------------------------------------- /06_Trading_Strategy/ch06_09_FirstScreenEx.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | import mplfinance as mpf 3 | from Investar import Analyzer 4 | 5 | mk = Analyzer.MarketDB() 6 | df = mk.get_daily_price('엔씨소프트', '2017-01-01', '2019-12-31') 7 | df.index = pd.to_datetime(df.date) 8 | df = df[['open', 'high', 'low', 'close', 'volume']] 9 | 10 | ema60 = df.close.ewm(span=60).mean() # ① 종가의 12주 지수 이동평균 11 | ema130 = df.close.ewm(span=130).mean() # ② 종가의 26주 지수 이동평균 12 | macd = ema60 - ema130 # ③ MACD선 13 | signal = macd.ewm(span=45).mean() # ④ 신호선(MACD의 9주 지수 이동평균) 14 | macdhist = macd - signal # ⑤ MACD 히스토그램 15 | 16 | apds = [mpf.make_addplot(ema130, color='c'), 17 | mpf.make_addplot(macdhist, type='bar', panel=1, color='m'), 18 | mpf.make_addplot(macd, panel=1, color='b'), 19 | mpf.make_addplot(signal, panel=1, color='g'), 20 | ] 21 | mc = mpf.make_marketcolors(up='r', down='b', inherit=True) 22 | stl = mpf.make_mpf_style(marketcolors=mc) 23 | mpf.plot(df, title='Triple Screen Trading - First Screen (NCSOFT)', type='candle', 24 | addplot=apds, figsize=(9,7), panel_ratios=(1,1), style=stl) 25 | -------------------------------------------------------------------------------- /06_Trading_Strategy/ch06_10_SecondScreen.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | import matplotlib.pyplot as plt 3 | import datetime 4 | from mpl_finance import candlestick_ohlc 5 | #from mplfinance.original_flavor import candlestick_ohlc 6 | import matplotlib.dates as mdates 7 | from Investar import Analyzer 8 | 9 | mk = Analyzer.MarketDB() 10 | df = mk.get_daily_price('엔씨소프트', '2017-01-01') 11 | 12 | ema60 = df.close.ewm(span=60).mean() 13 | ema130 = df.close.ewm(span=130).mean() 14 | macd = ema60 - ema130 15 | signal = macd.ewm(span=45).mean() 16 | macdhist = macd - signal 17 | 18 | df = df.assign(ema130=ema130, ema60=ema60, macd=macd, signal=signal, 19 | macdhist=macdhist).dropna() 20 | df['number'] = df.index.map(mdates.date2num) 21 | ohlc = df[['number','open','high','low','close']] 22 | 23 | ndays_high = df.high.rolling(window=14, min_periods=1).max() # ① 24 | ndays_low = df.low.rolling(window=14, min_periods=1).min() # ② 25 | fast_k = (df.close - ndays_low) / (ndays_high - ndays_low) * 100 # ③ 26 | slow_d= fast_k.rolling(window=3).mean() # ④ 27 | df = df.assign(fast_k=fast_k, slow_d=slow_d).dropna() # ⑤ 28 | 29 | plt.figure(figsize=(9, 7)) 30 | p1 = plt.subplot(2, 1, 1) 31 | plt.title('Triple Screen Trading - Second Screen (NCSOFT)') 32 | plt.grid(True) 33 | candlestick_ohlc(p1, ohlc.values, width=.6, colorup='red', colordown='blue') 34 | p1.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m')) 35 | plt.plot(df.number, df['ema130'], color='c', label='EMA130') 36 | plt.legend(loc='best') 37 | p1 = plt.subplot(2, 1, 2) 38 | plt.grid(True) 39 | p1.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m')) 40 | plt.plot(df.number, df['fast_k'], color='c', label='%K') 41 | plt.plot(df.number, df['slow_d'], color='k', label='%D') 42 | plt.yticks([0, 20, 80, 100]) # ⑥ 43 | plt.legend(loc='best') 44 | plt.show() 45 | -------------------------------------------------------------------------------- /06_Trading_Strategy/ch06_11_TripleScreen.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | import matplotlib.pyplot as plt 3 | import datetime 4 | from mpl_finance import candlestick_ohlc 5 | #from mplfinance.original_flavor import candlestick_ohlc 6 | import matplotlib.dates as mdates 7 | from Investar import Analyzer 8 | 9 | mk = Analyzer.MarketDB() 10 | df = mk.get_daily_price('엔씨소프트', '2017-01-01') 11 | 12 | ema60 = df.close.ewm(span=60).mean() 13 | ema130 = df.close.ewm(span=130).mean() 14 | macd = ema60 - ema130 15 | signal = macd.ewm(span=45).mean() 16 | macdhist = macd - signal 17 | df = df.assign(ema130=ema130, ema60=ema60, macd=macd, signal=signal, macdhist=macdhist).dropna() 18 | 19 | df['number'] = df.index.map(mdates.date2num) 20 | ohlc = df[['number','open','high','low','close']] 21 | 22 | ndays_high = df.high.rolling(window=14, min_periods=1).max() 23 | ndays_low = df.low.rolling(window=14, min_periods=1).min() 24 | 25 | fast_k = (df.close - ndays_low) / (ndays_high - ndays_low) * 100 26 | slow_d = fast_k.rolling(window=3).mean() 27 | df = df.assign(fast_k=fast_k, slow_d=slow_d).dropna() 28 | 29 | plt.figure(figsize=(9, 9)) 30 | p1 = plt.subplot(3, 1, 1) 31 | plt.title('Triple Screen Trading (NCSOFT)') 32 | plt.grid(True) 33 | candlestick_ohlc(p1, ohlc.values, width=.6, colorup='red', colordown='blue') 34 | p1.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m')) 35 | plt.plot(df.number, df['ema130'], color='c', label='EMA130') 36 | for i in range(1, len(df.close)): 37 | if df.ema130.values[i-1] < df.ema130.values[i] and \ 38 | df.slow_d.values[i-1] >= 20 and df.slow_d.values[i] < 20: 39 | plt.plot(df.number.values[i], 250000, 'r^') 40 | elif df.ema130.values[i-1] > df.ema130.values[i] and \ 41 | df.slow_d.values[i-1] <= 80 and df.slow_d.values[i] > 80: 42 | plt.plot(df.number.values[i], 250000, 'bv') 43 | plt.legend(loc='best') 44 | 45 | p2 = plt.subplot(3, 1, 2) 46 | plt.grid(True) 47 | p2.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m')) 48 | plt.bar(df.number, df['macdhist'], color='m', label='MACD-Hist') 49 | plt.plot(df.number, df['macd'], color='b', label='MACD') 50 | plt.plot(df.number, df['signal'], 'g--', label='MACD-Signal') 51 | plt.legend(loc='best') 52 | 53 | p3 = plt.subplot(3, 1, 3) 54 | plt.grid(True) 55 | p3.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m')) 56 | plt.plot(df.number, df['fast_k'], color='c', label='%K') 57 | plt.plot(df.number, df['slow_d'], color='k', label='%D') 58 | plt.yticks([0, 20, 80, 100]) 59 | plt.legend(loc='best') 60 | plt.show() 61 | -------------------------------------------------------------------------------- /06_Trading_Strategy/ch06_12_DualMomentum.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | import pymysql 3 | from datetime import datetime 4 | from datetime import timedelta 5 | from Investar import Analyzer 6 | 7 | class DualMomentum: 8 | def __init__(self): 9 | """생성자: KRX 종목코드(codes)를 구하기 위한 MarkgetDB 객체 생성""" 10 | self.mk = Analyzer.MarketDB() 11 | 12 | def get_rltv_momentum(self, start_date, end_date, stock_count): 13 | """특정 기간 동안 수익률이 제일 높았던 stock_count 개의 종목들 (상대 모멘텀) 14 | - start_date : 상대 모멘텀을 구할 시작일자 ('2020-01-01') 15 | - end_date : 상대 모멘텀을 구할 종료일자 ('2020-12-31') 16 | - stock_count : 상대 모멘텀을 구할 종목수 17 | """ 18 | connection = pymysql.connect(host='localhost', port=3306, 19 | db='INVESTAR', user='root', passwd='******', autocommit=True) 20 | cursor = connection.cursor() 21 | 22 | # 사용자가 입력한 시작일자를 DB에서 조회되는 일자로 보정 23 | sql = f"select max(date) from daily_price where date <= '{start_date}'" 24 | cursor.execute(sql) 25 | result = cursor.fetchone() 26 | if (result[0] is None): 27 | print ("start_date : {} -> returned None".format(sql)) 28 | return 29 | start_date = result[0].strftime('%Y-%m-%d') 30 | 31 | 32 | # 사용자가 입력한 종료일자를 DB에서 조회되는 일자로 보정 33 | sql = f"select max(date) from daily_price where date <= '{end_date}'" 34 | cursor.execute(sql) 35 | result = cursor.fetchone() 36 | if (result[0] is None): 37 | print ("end_date : {} -> returned None".format(sql)) 38 | return 39 | end_date = result[0].strftime('%Y-%m-%d') 40 | 41 | 42 | # KRX 종목별 수익률을 구해서 2차원 리스트 형태로 추가 43 | rows = [] 44 | columns = ['code', 'company', 'old_price', 'new_price', 'returns'] 45 | for _, code in enumerate(self.mk.codes): 46 | sql = f"select close from daily_price "\ 47 | f"where code='{code}' and date='{start_date}'" 48 | cursor.execute(sql) 49 | result = cursor.fetchone() 50 | if (result is None): 51 | continue 52 | old_price = int(result[0]) 53 | sql = f"select close from daily_price "\ 54 | f"where code='{code}' and date='{end_date}'" 55 | cursor.execute(sql) 56 | result = cursor.fetchone() 57 | if (result is None): 58 | continue 59 | new_price = int(result[0]) 60 | returns = (new_price / old_price - 1) * 100 61 | rows.append([code, self.mk.codes[code], old_price, new_price, 62 | returns]) 63 | 64 | 65 | # 상대 모멘텀 데이터프레임을 생성한 후 수익률순으로 출력 66 | df = pd.DataFrame(rows, columns=columns) 67 | df = df[['code', 'company', 'old_price', 'new_price', 'returns']] 68 | df = df.sort_values(by='returns', ascending=False) 69 | df = df.head(stock_count) 70 | df.index = pd.Index(range(stock_count)) 71 | connection.close() 72 | print(df) 73 | print(f"\nRelative momentum ({start_date} ~ {end_date}) : "\ 74 | f"{df['returns'].mean():.2f}% \n") 75 | return df 76 | 77 | def get_abs_momentum(self, rltv_momentum, start_date, end_date): 78 | """특정 기간 동안 상대 모멘텀에 투자했을 때의 평균 수익률 (절대 모멘텀) 79 | - rltv_momentum : get_rltv_momentum() 함수의 리턴값 (상대 모멘텀) 80 | - start_date : 절대 모멘텀을 구할 매수일 ('2020-01-01') 81 | - end_date : 절대 모멘텀을 구할 매도일 ('2020-12-31') 82 | """ 83 | stockList = list(rltv_momentum['code']) 84 | connection = pymysql.connect(host='localhost', port=3306, 85 | db='INVESTAR', user='root', passwd='******', autocommit=True) 86 | cursor = connection.cursor() 87 | 88 | 89 | # 사용자가 입력한 매수일을 DB에서 조회되는 일자로 변경 90 | sql = f"select max(date) from daily_price "\ 91 | f"where date <= '{start_date}'" 92 | cursor.execute(sql) 93 | result = cursor.fetchone() 94 | if (result[0] is None): 95 | print ("{} -> returned None".format(sql)) 96 | return 97 | start_date = result[0].strftime('%Y-%m-%d') 98 | 99 | 100 | # 사용자가 입력한 매도일을 DB에서 조회되는 일자로 변경 101 | sql = f"select max(date) from daily_price "\ 102 | f"where date <= '{end_date}'" 103 | cursor.execute(sql) 104 | result = cursor.fetchone() 105 | if (result[0] is None): 106 | print ("{} -> returned None".format(sql)) 107 | return 108 | end_date = result[0].strftime('%Y-%m-%d') 109 | 110 | 111 | # 상대 모멘텀의 종목별 수익률을 구해서 2차원 리스트 형태로 추가 112 | rows = [] 113 | columns = ['code', 'company', 'old_price', 'new_price', 'returns'] 114 | for _, code in enumerate(stockList): 115 | sql = f"select close from daily_price "\ 116 | f"where code='{code}' and date='{start_date}'" 117 | cursor.execute(sql) 118 | result = cursor.fetchone() 119 | if (result is None): 120 | continue 121 | old_price = int(result[0]) 122 | sql = f"select close from daily_price "\ 123 | f"where code='{code}' and date='{end_date}'" 124 | cursor.execute(sql) 125 | result = cursor.fetchone() 126 | if (result is None): 127 | continue 128 | new_price = int(result[0]) 129 | returns = (new_price / old_price - 1) * 100 130 | rows.append([code, self.mk.codes[code], old_price, new_price, 131 | returns]) 132 | 133 | 134 | # 절대 모멘텀 데이터프레임을 생성한 후 수익률순으로 출력 135 | df = pd.DataFrame(rows, columns=columns) 136 | df = df[['code', 'company', 'old_price', 'new_price', 'returns']] 137 | df = df.sort_values(by='returns', ascending=False) 138 | connection.close() 139 | print(df) 140 | print(f"\nAbasolute momentum ({start_date} ~ {end_date}) : "\ 141 | f"{df['returns'].mean():.2f}%") 142 | return 143 | -------------------------------------------------------------------------------- /06_Trading_Strategy/imgs/AbsoluteMomentum.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/06_Trading_Strategy/imgs/AbsoluteMomentum.jpg -------------------------------------------------------------------------------- /06_Trading_Strategy/imgs/BollingerBand.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/06_Trading_Strategy/imgs/BollingerBand.jpg -------------------------------------------------------------------------------- /06_Trading_Strategy/imgs/BollingerBand_BandWidth.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/06_Trading_Strategy/imgs/BollingerBand_BandWidth.jpg -------------------------------------------------------------------------------- /06_Trading_Strategy/imgs/BollingerBand_IIP21.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/06_Trading_Strategy/imgs/BollingerBand_IIP21.jpg -------------------------------------------------------------------------------- /06_Trading_Strategy/imgs/BollingerBand_MFI.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/06_Trading_Strategy/imgs/BollingerBand_MFI.jpg -------------------------------------------------------------------------------- /06_Trading_Strategy/imgs/BollingerBand_PercentB.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/06_Trading_Strategy/imgs/BollingerBand_PercentB.jpg -------------------------------------------------------------------------------- /06_Trading_Strategy/imgs/BollingerBand_Reversals.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/06_Trading_Strategy/imgs/BollingerBand_Reversals.jpg -------------------------------------------------------------------------------- /06_Trading_Strategy/imgs/BollingerBand_TrendFollowing.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/06_Trading_Strategy/imgs/BollingerBand_TrendFollowing.jpg -------------------------------------------------------------------------------- /06_Trading_Strategy/imgs/BollingerBand_TrendFollowing_Naver.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/06_Trading_Strategy/imgs/BollingerBand_TrendFollowing_Naver.jpg -------------------------------------------------------------------------------- /06_Trading_Strategy/imgs/BollingerOnBollingerBands.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/06_Trading_Strategy/imgs/BollingerOnBollingerBands.jpg -------------------------------------------------------------------------------- /06_Trading_Strategy/imgs/DualMomentum.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/06_Trading_Strategy/imgs/DualMomentum.jpg -------------------------------------------------------------------------------- /06_Trading_Strategy/imgs/DualMomentumInvesting.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/06_Trading_Strategy/imgs/DualMomentumInvesting.jpg -------------------------------------------------------------------------------- /06_Trading_Strategy/imgs/FirstScreen.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/06_Trading_Strategy/imgs/FirstScreen.jpg -------------------------------------------------------------------------------- /06_Trading_Strategy/imgs/Long-TermSecretsToShort-TermTrading.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/06_Trading_Strategy/imgs/Long-TermSecretsToShort-TermTrading.jpg -------------------------------------------------------------------------------- /06_Trading_Strategy/imgs/Portpolio_optimization.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/06_Trading_Strategy/imgs/Portpolio_optimization.jpg -------------------------------------------------------------------------------- /06_Trading_Strategy/imgs/RelativeMomentum.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/06_Trading_Strategy/imgs/RelativeMomentum.jpg -------------------------------------------------------------------------------- /06_Trading_Strategy/imgs/SecondScreen.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/06_Trading_Strategy/imgs/SecondScreen.jpg -------------------------------------------------------------------------------- /06_Trading_Strategy/imgs/TheNewTradingForALiving.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/06_Trading_Strategy/imgs/TheNewTradingForALiving.jpg -------------------------------------------------------------------------------- /06_Trading_Strategy/imgs/TripleScreen.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/06_Trading_Strategy/imgs/TripleScreen.jpg -------------------------------------------------------------------------------- /06_Trading_Strategy/imgs/ch06_EfficientFrontierLine.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/06_Trading_Strategy/imgs/ch06_EfficientFrontierLine.jpg -------------------------------------------------------------------------------- /06_Trading_Strategy/imgs/efficient_frontier.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/06_Trading_Strategy/imgs/efficient_frontier.jpg -------------------------------------------------------------------------------- /07_Django_and_Automation/ch07_01_index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | This is title. 4 | 5 | 6 |

This is heading1 text.

7 |

This is heading2 text.

8 |

This is heading3 text.

9 |

This is a paragraph.

10 | This is plain text.
11 | This is bold text.
12 | This is Italic text.
13 | This is strike text.
14 |
    15 |
  1. the first orderd list
  2. 16 |
  3. the second orderd list
  4. 17 |
  5. the third orderd list
  6. 18 |
19 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 |
table header 1table header 2table header 3
table data 4table data 5table data 6
table data 7table data 8table data 9

41 | Visit Django homepage!
42 |
43 | 44 | -------------------------------------------------------------------------------- /07_Django_and_Automation/ch07_02_index.html: -------------------------------------------------------------------------------- 1 | {% load static %} 2 | 3 | 4 | This is title. 5 | 6 | 7 | 8 |

This is heading1 text.

9 |

This is heading2 text.

10 |

This is heading3 text.

11 |

This is a paragraph.

12 | This is plain text.
13 | This is bold text.
14 | This is Italic text.
15 | This is strike text.
16 |
    17 |
  1. the first orderd list
  2. 18 |
  3. the second orderd list
  4. 19 |
  5. the third orderd list
  6. 20 |
21 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 |
table header 1table header 2table header 3
table data 4table data 5table data 6
table data 7table data 8table data 9

43 | Visit Django homepage!
44 |
45 | 46 | 47 | -------------------------------------------------------------------------------- /07_Django_and_Automation/ch07_03_style.css: -------------------------------------------------------------------------------- 1 | /* 테이블 데이터와 테이블 헤더에 대한 스타일 지정 */ 2 | table td, table th { 3 | border: 1px solid #ddd; 4 | padding: 8px; 5 | } 6 | 7 | /* 테이블 행이 짝수 번째일 경우의 색상 지정 */ 8 | table tr:nth-child(even){background-color: #f2f2f2;} 9 | 10 | /* 테이블 행에 마우스 커서를 올렸을 때의 색상 지정 */ 11 | table tr:hover {background-color: #ddd;} 12 | 13 | /* 테이블 헤더에 대한 스타일 지정 */ 14 | table th { 15 | padding-top: 12px; 16 | padding-bottom: 12px; 17 | text-align: left; 18 | background-color: #4CAF50; 19 | color: white; 20 | } 21 | -------------------------------------------------------------------------------- /07_Django_and_Automation/ch07_04_balance_views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | from bs4 import BeautifulSoup 3 | from urllib.request import urlopen 4 | 5 | def get_data(symbol): 6 | url = 'http://finance.naver.com/item/sise.nhn?code={}'.format(symbol) 7 | with urlopen(url) as doc: 8 | soup = BeautifulSoup(doc, "lxml", from_encoding="euc-kr") 9 | cur_price = soup.find('strong', id='_nowVal') # ① 10 | cur_rate = soup.find('strong', id='_rate') # ② 11 | stock = soup.find('title') # ③ 12 | stock_name = stock.text.split(':')[0].strip() # ④ 13 | return cur_price.text, cur_rate.text.strip(), stock_name 14 | 15 | def main_view(request): 16 | querydict = request.GET.copy() 17 | mylist = querydict.lists() # ⑤ 18 | rows = [] 19 | total = 0 20 | 21 | for x in mylist: 22 | cur_price, cur_rate, stock_name = get_data(x[0]) # ⑥ 23 | price = cur_price.replace(',', '') 24 | stock_count = format(int(x[1][0]), ',') # ⑦ 25 | sum = int(price) * int(x[1][0]) 26 | stock_sum = format(sum, ',') 27 | rows.append([stock_name, x[0], cur_price, stock_count, cur_rate, 28 | stock_sum]) # ⑧ 29 | total = total + int(price) * int(x[1][0]) # ⑨ 30 | 31 | total_amount = format(total, ',') 32 | values = {'rows' : rows, 'total' : total_amount} # ⑩ 33 | return render(request, 'balance.html', values) # ⑪ 34 | -------------------------------------------------------------------------------- /07_Django_and_Automation/ch07_05_balance.html: -------------------------------------------------------------------------------- 1 | {% load static %} 2 | 3 | 4 | Balance: {{ total }} 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | {% for row in rows %} 18 | 19 | {% for x in row %} 20 | 21 | {% endfor %} 22 | 23 | {% endfor %} 24 | 25 | 26 | 27 | 28 |
종목명종목코드현재가주식수등락률평가금액
{{ x }}
계좌 잔고{{ total }}
29 | 30 | -------------------------------------------------------------------------------- /07_Django_and_Automation/ch07_06_b_style.css: -------------------------------------------------------------------------------- 1 | /* 테이블 폰트 및 테두리선 설정 */ 2 | table { 3 | font-family: Arial, Helvetica, sans-serif; 4 | border-collapse: collapse; 5 | } 6 | 7 | /* 테이블 데이터 및 테이블 헤더 설정 */ 8 | table td, table th { 9 | border: 1px solid #ddd; 10 | padding: 8px; 11 | } 12 | 13 | /* 테이블 행이 짝수 번째일 때의 색상 지정 */ 14 | table tr:nth-child(even){background-color: #f2f2f2;} 15 | 16 | /* 테이블 행 위에 마우스 컬러가 올려졌을 때의 색상 지정 */ 17 | table tr:hover {background-color: #ddd;} 18 | 19 | /* 테이블 헤더의 스타일 지정 */ 20 | table th { 21 | padding-top: 12px; 22 | padding-bottom: 12px; 23 | background-color: #4D92AA; 24 | text-align: center; 25 | color: white; 26 | } 27 | 28 | /* 테이블 데이터의 텍스트 정렬 방식을 지정 */ 29 | table td:nth-child(1){text-align: left;} 30 | table td:nth-child(2){text-align: center;} 31 | table td:nth-child(3){text-align: right;} 32 | table td:nth-child(4){text-align: right;} 33 | table td:nth-child(5){text-align: right;} 34 | table td:nth-child(6){text-align: right;} -------------------------------------------------------------------------------- /07_Django_and_Automation/ch07_07_Slack_SendMessage.py: -------------------------------------------------------------------------------- 1 | from slacker import Slacker 2 | slack = Slacker('xoxb-341411373331-856655856231-e6wtlNsuv384K9fjtaIS7WiL') 3 | 4 | markdown_text = ''' 5 | This message is plain. 6 | *This message is bold.* 7 | `This message is code.` 8 | _This message is italic._ 9 | ~This message is strike.~ 10 | ''' 11 | 12 | attach_dict = { 13 | 'color' :'#ff0000', 14 | 'author_name':'INVESTAR', 15 | "author_link":'github.com/investar', 16 | 'title' :'오늘의 증시 KOSPI', 17 | 'title_link' :'http://finance.naver.com/sise/sise_index.nhn?code=KOSPI', 18 | 'text' :'2,326.13 △11.89 (+0.51%)', 19 | 'image_url' :'ssl.pstatic.net/imgstock/chart3/day/KOSPI.png' 20 | } 21 | 22 | attach_list = [attach_dict] 23 | slack.chat.post_message(channel="#general", text=markdown_text, attachments=attach_list) -------------------------------------------------------------------------------- /07_Django_and_Automation/ch07_08_Backtrader_RSI.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | import backtrader as bt 3 | 4 | class MyStrategy(bt.Strategy): # ① 5 | def __init__(self): 6 | self.rsi = bt.indicators.RSI(self.data.close) # ② 7 | def next(self): # ③ 8 | if not self.position: 9 | if self.rsi < 30: 10 | self.order = self.buy() 11 | else: 12 | if self.rsi > 70: 13 | self.order = self.sell() 14 | 15 | cerebro = bt.Cerebro() # ④ 16 | cerebro.addstrategy(MyStrategy) 17 | data = bt.feeds.YahooFinanceData(dataname='036570.KS', # ⑤ 18 | fromdate=datetime(2017, 1, 1), todate=datetime(2019, 12, 1)) 19 | cerebro.adddata(data) 20 | cerebro.broker.setcash(10000000) # ⑥ 21 | cerebro.addsizer(bt.sizers.SizerFix, stake=30) # ⑦ 22 | 23 | print(f'Initial Portfolio Value : {cerebro.broker.getvalue():,.0f} KRW') 24 | cerebro.run() # ⑧ 25 | print(f'Final Portfolio Value : {cerebro.broker.getvalue():,.0f} KRW') 26 | cerebro.plot() # ⑨ -------------------------------------------------------------------------------- /07_Django_and_Automation/ch07_09_Backtrader_RSI_SMA.py: -------------------------------------------------------------------------------- 1 | import backtrader as bt 2 | from datetime import datetime 3 | 4 | class MyStrategy(bt.Strategy): 5 | def __init__(self): 6 | self.dataclose = self.datas[0].close 7 | self.order = None 8 | self.buyprice = None 9 | self.buycomm = None 10 | self.rsi = bt.indicators.RSI_SMA(self.data.close, period=21) 11 | 12 | def notify_order(self, order): # ① 13 | if order.status in [order.Submitted, order.Accepted]: 14 | return 15 | if order.status in [order.Completed]: # ② 16 | if order.isbuy(): 17 | self.log(f'BUY : 주가 {order.executed.price:,.0f}, ' 18 | f'수량 {order.executed.size:,.0f}, ' 19 | f'수수료 {order.executed.comm:,.0f}, ' 20 | f'자산 {cerebro.broker.getvalue():,.0f}') 21 | self.buyprice = order.executed.price 22 | self.buycomm = order.executed.comm 23 | else: 24 | self.log(f'SELL : 주가 {order.executed.price:,.0f}, ' 25 | f'수량 {order.executed.size:,.0f}, ' 26 | f'수수료 {order.executed.comm:,.0f}, ' 27 | f'자산 {cerebro.broker.getvalue():,.0f}') 28 | self.bar_executed = len(self) 29 | elif order.status in [order.Canceled]: 30 | self.log('ORDER CANCELD') 31 | elif order.status in [order.Margin]: 32 | self.log('ORDER MARGIN') 33 | elif order.status in [order.Rejected]: 34 | self.log('ORDER REJECTED') 35 | self.order = None 36 | 37 | def next(self): 38 | if not self.position: 39 | if self.rsi < 30: 40 | self.order = self.buy() 41 | else: 42 | if self.rsi > 70: 43 | self.order = self.sell() 44 | 45 | def log(self, txt, dt=None): # ③ 46 | dt = self.datas[0].datetime.date(0) 47 | print(f'[{dt.isoformat()}] {txt}') 48 | 49 | cerebro = bt.Cerebro() 50 | cerebro.addstrategy(MyStrategy) 51 | data = bt.feeds.YahooFinanceData(dataname='036570.KS', 52 | fromdate=datetime(2017, 1, 1), todate=datetime(2019, 12, 1)) 53 | cerebro.adddata(data) 54 | cerebro.broker.setcash(10000000) 55 | cerebro.broker.setcommission(commission=0.0014) # ④ 56 | cerebro.addsizer(bt.sizers.PercentSizer, percents=90) # ⑤ 57 | 58 | print(f'Initial Portfolio Value : {cerebro.broker.getvalue():,.0f} KRW') 59 | cerebro.run() 60 | print(f'Final Portfolio Value : {cerebro.broker.getvalue():,.0f} KRW') 61 | cerebro.plot(style='candlestick') # ⑥ -------------------------------------------------------------------------------- /07_Django_and_Automation/imgs/BackTrader_PlotRSISMA.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/07_Django_and_Automation/imgs/BackTrader_PlotRSISMA.jpg -------------------------------------------------------------------------------- /07_Django_and_Automation/imgs/Backtrader_Homepage.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/07_Django_and_Automation/imgs/Backtrader_Homepage.jpg -------------------------------------------------------------------------------- /07_Django_and_Automation/imgs/Backtrader_PlotRSI.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/07_Django_and_Automation/imgs/Backtrader_PlotRSI.jpg -------------------------------------------------------------------------------- /07_Django_and_Automation/imgs/Balance_Naver.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/07_Django_and_Automation/imgs/Balance_Naver.jpg -------------------------------------------------------------------------------- /07_Django_and_Automation/imgs/Balance_Sample2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/07_Django_and_Automation/imgs/Balance_Sample2.jpg -------------------------------------------------------------------------------- /07_Django_and_Automation/imgs/Django_AdminLogin.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/07_Django_and_Automation/imgs/Django_AdminLogin.jpg -------------------------------------------------------------------------------- /07_Django_and_Automation/imgs/Django_AdminPage.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/07_Django_and_Automation/imgs/Django_AdminPage.jpg -------------------------------------------------------------------------------- /07_Django_and_Automation/imgs/Django_Hello.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/07_Django_and_Automation/imgs/Django_Hello.jpg -------------------------------------------------------------------------------- /07_Django_and_Automation/imgs/Django_Homepage.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/07_Django_and_Automation/imgs/Django_Homepage.jpg -------------------------------------------------------------------------------- /07_Django_and_Automation/imgs/Django_IndexPage.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/07_Django_and_Automation/imgs/Django_IndexPage.jpg -------------------------------------------------------------------------------- /07_Django_and_Automation/imgs/Django_IndexTree.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/07_Django_and_Automation/imgs/Django_IndexTree.jpg -------------------------------------------------------------------------------- /07_Django_and_Automation/imgs/Django_Logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/07_Django_and_Automation/imgs/Django_Logo.jpg -------------------------------------------------------------------------------- /07_Django_and_Automation/imgs/Django_PIP.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/07_Django_and_Automation/imgs/Django_PIP.jpg -------------------------------------------------------------------------------- /07_Django_and_Automation/imgs/Django_Python.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/07_Django_and_Automation/imgs/Django_Python.jpg -------------------------------------------------------------------------------- /07_Django_and_Automation/imgs/Django_Rocket.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/07_Django_and_Automation/imgs/Django_Rocket.jpg -------------------------------------------------------------------------------- /07_Django_and_Automation/imgs/Django_StaticImage.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/07_Django_and_Automation/imgs/Django_StaticImage.jpg -------------------------------------------------------------------------------- /07_Django_and_Automation/imgs/Django_Superuser.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/07_Django_and_Automation/imgs/Django_Superuser.jpg -------------------------------------------------------------------------------- /07_Django_and_Automation/imgs/Django_Tree.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/07_Django_and_Automation/imgs/Django_Tree.jpg -------------------------------------------------------------------------------- /07_Django_and_Automation/imgs/Slack_Bots.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/07_Django_and_Automation/imgs/Slack_Bots.jpg -------------------------------------------------------------------------------- /07_Django_and_Automation/imgs/Slack_CreateApp.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/07_Django_and_Automation/imgs/Slack_CreateApp.jpg -------------------------------------------------------------------------------- /07_Django_and_Automation/imgs/Slack_Scopes.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/07_Django_and_Automation/imgs/Slack_Scopes.jpg -------------------------------------------------------------------------------- /07_Django_and_Automation/imgs/Slack_SmartPhone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/07_Django_and_Automation/imgs/Slack_SmartPhone.png -------------------------------------------------------------------------------- /07_Django_and_Automation/imgs/Slack_mySlackBot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/07_Django_and_Automation/imgs/Slack_mySlackBot.jpg -------------------------------------------------------------------------------- /08_Volatility_Breakout/ch08_01_AutoConnect.py: -------------------------------------------------------------------------------- 1 | from pywinauto import application 2 | import time 3 | import os 4 | 5 | os.system('taskkill /IM coStarter* /F /T') 6 | os.system('taskkill /IM CpStart* /F /T') 7 | os.system('taskkill /IM DibServer* /F /T') 8 | os.system('wmic process where "name like \'%coStarter%\'" call terminate') 9 | os.system('wmic process where "name like \'%CpStart%\'" call terminate') 10 | os.system('wmic process where "name like \'%DibServer%\'" call terminate') 11 | time.sleep(5) 12 | 13 | app = application.Application() 14 | app.start('C:\CREON\STARTER\coStarter.exe /prj:cp /id:userid /pwd:pa$$word /pwdcert:certPa$$word /autostart') 15 | time.sleep(60) 16 | -------------------------------------------------------------------------------- /08_Volatility_Breakout/ch08_02_DynamicPageScraping_NaverETF.py: -------------------------------------------------------------------------------- 1 | from selenium import webdriver 2 | from bs4 import BeautifulSoup 3 | import pandas as pd 4 | 5 | # 옵션값 설정 6 | opt = webdriver.ChromeOptions() 7 | opt.add_argument('headless') 8 | 9 | # 웹드라이버를 통해 네이버 금융 ETF 페이지에 접속 10 | drv = webdriver.Chrome('C:\myPackage\chromedriver.exe', options=opt) 11 | drv.implicitly_wait(3) 12 | drv.get('https://finance.naver.com/sise/etf.nhn') 13 | 14 | # 뷰티풀 수프로 테이블을 스크래핑 15 | bs = BeautifulSoup(drv.page_source, 'lxml') 16 | drv.quit() 17 | table = bs.find_all("table", class_="type_1 type_etf") 18 | df = pd.read_html(str(table), header=0)[0] 19 | 20 | # 불필요한 열과 행을 삭제하고 인덱스를 재설정해서 출력 21 | df = df.drop(columns=['Unnamed: 9']) 22 | df = df.dropna() 23 | df.index = range(1, len(df)+1) 24 | print(df) 25 | 26 | # 링크 주소에 포함된 종목코드를 추출하여 전체 종목코드와 종목명 출력 27 | etf_td = bs.find_all("td", class_="ctg") 28 | etfs = {} 29 | for td in etf_td: 30 | s = str(td.a["href"]).split('=') 31 | code = s[-1] 32 | etfs[td.a.text] = code 33 | print("etfs :", etfs) -------------------------------------------------------------------------------- /08_Volatility_Breakout/ch08_03_EtfAlgoTrader.py: -------------------------------------------------------------------------------- 1 | import os, sys, ctypes 2 | import win32com.client 3 | import pandas as pd 4 | from datetime import datetime 5 | from slacker import Slacker 6 | import time, calendar 7 | from bs4 import BeautifulSoup 8 | from urllib.request import urlopen 9 | from selenium import webdriver 10 | from selenium.webdriver.chrome.options import Options 11 | 12 | slack = Slacker('xoxb-341411373331-390645946323-wPFYKNbhlgef4bMUiP1CvSyX') 13 | def dbgout(message): 14 | """인자로 받은 문자열을 파이썬 셸과 슬랙으로 동시에 출력한다.""" 15 | print(datetime.now().strftime('[%m/%d %H:%M:%S]'), message) 16 | strbuf = datetime.now().strftime('[%m/%d %H:%M:%S] ') + message 17 | slack.chat.post_message('#etf-algo-trading', strbuf) 18 | 19 | def printlog(message, *args): 20 | """인자로 받은 문자열을 파이썬 셸에 출력한다.""" 21 | print(datetime.now().strftime('[%m/%d %H:%M:%S]'), message, *args) 22 | 23 | # 크레온 플러스 공통 OBJECT 24 | cpCodeMgr = win32com.client.Dispatch('CpUtil.CpStockCode') 25 | cpStatus = win32com.client.Dispatch('CpUtil.CpCybos') 26 | cpTradeUtil = win32com.client.Dispatch('CpTrade.CpTdUtil') 27 | cpStock = win32com.client.Dispatch('DsCbo1.StockMst') 28 | cpOhlc = win32com.client.Dispatch('CpSysDib.StockChart') 29 | cpBalance = win32com.client.Dispatch('CpTrade.CpTd6033') 30 | cpCash = win32com.client.Dispatch('CpTrade.CpTdNew5331A') 31 | cpOrder = win32com.client.Dispatch('CpTrade.CpTd0311') 32 | 33 | def check_creon_system(): 34 | """크레온 플러스 시스템 연결 상태를 점검한다.""" 35 | # 관리자 권한으로 프로세스 실행 여부 36 | if not ctypes.windll.shell32.IsUserAnAdmin(): 37 | printlog('check_creon_system() : admin user -> FAILED') 38 | return False 39 | 40 | # 연결 여부 체크 41 | if (cpStatus.IsConnect == 0): 42 | printlog('check_creon_system() : connect to server -> FAILED') 43 | return False 44 | 45 | # 주문 관련 초기화 - 계좌 관련 코드가 있을 때만 사용 46 | if (cpTradeUtil.TradeInit(0) != 0): 47 | printlog('check_creon_system() : init trade -> FAILED') 48 | return False 49 | return True 50 | 51 | def get_current_price(code): 52 | """인자로 받은 종목의 현재가, 매도호가, 매수호가를 반환한다.""" 53 | cpStock.SetInputValue(0, code) # 종목코드에 대한 가격 정보 54 | cpStock.BlockRequest() 55 | item = {} 56 | item['cur_price'] = cpStock.GetHeaderValue(11) # 현재가 57 | item['ask'] = cpStock.GetHeaderValue(16) # 매도호가 58 | item['bid'] = cpStock.GetHeaderValue(17) # 매수호가 59 | return item['cur_price'], item['ask'], item['bid'] 60 | 61 | def get_ohlc(code, qty): 62 | """인자로 받은 종목의 OHLC 가격 정보를 qty 개수만큼 반환한다.""" 63 | cpOhlc.SetInputValue(0, code) # 종목코드 64 | cpOhlc.SetInputValue(1, ord('2')) # 1:기간, 2:개수 65 | cpOhlc.SetInputValue(4, qty) # 요청개수 66 | cpOhlc.SetInputValue(5, [0, 2, 3, 4, 5]) # 0:날짜, 2~5:OHLC 67 | cpOhlc.SetInputValue(6, ord('D')) # D:일단위 68 | cpOhlc.SetInputValue(9, ord('1')) # 0:무수정주가, 1:수정주가 69 | cpOhlc.BlockRequest() 70 | count = cpOhlc.GetHeaderValue(3) # 3:수신개수 71 | columns = ['open', 'high', 'low', 'close'] 72 | index = [] 73 | rows = [] 74 | for i in range(count): 75 | index.append(cpOhlc.GetDataValue(0, i)) 76 | rows.append([cpOhlc.GetDataValue(1, i), cpOhlc.GetDataValue(2, i), 77 | cpOhlc.GetDataValue(3, i), cpOhlc.GetDataValue(4, i)]) 78 | df = pd.DataFrame(rows, columns=columns, index=index) 79 | return df 80 | 81 | def get_stock_balance(code): 82 | """인자로 받은 종목의 종목명과 수량을 반환한다.""" 83 | cpTradeUtil.TradeInit() 84 | acc = cpTradeUtil.AccountNumber[0] # 계좌번호 85 | accFlag = cpTradeUtil.GoodsList(acc, 1) # -1:전체, 1:주식, 2:선물/옵션 86 | cpBalance.SetInputValue(0, acc) # 계좌번호 87 | cpBalance.SetInputValue(1, accFlag[0]) # 상품구분 - 주식 상품 중 첫번째 88 | cpBalance.SetInputValue(2, 50) # 요청 건수(최대 50) 89 | cpBalance.BlockRequest() 90 | if code == 'ALL': 91 | dbgout('계좌명: ' + str(cpBalance.GetHeaderValue(0))) 92 | dbgout('결제잔고수량 : ' + str(cpBalance.GetHeaderValue(1))) 93 | dbgout('평가금액: ' + str(cpBalance.GetHeaderValue(3))) 94 | dbgout('평가손익: ' + str(cpBalance.GetHeaderValue(4))) 95 | dbgout('종목수: ' + str(cpBalance.GetHeaderValue(7))) 96 | stocks = [] 97 | for i in range(cpBalance.GetHeaderValue(7)): 98 | stock_code = cpBalance.GetDataValue(12, i) # 종목코드 99 | stock_name = cpBalance.GetDataValue(0, i) # 종목명 100 | stock_qty = cpBalance.GetDataValue(15, i) # 수량 101 | if code == 'ALL': 102 | dbgout(str(i+1) + ' ' + stock_code + '(' + stock_name + ')' 103 | + ':' + str(stock_qty)) 104 | stocks.append({'code': stock_code, 'name': stock_name, 105 | 'qty': stock_qty}) 106 | if stock_code == code: 107 | return stock_name, stock_qty 108 | if code == 'ALL': 109 | return stocks 110 | else: 111 | stock_name = cpCodeMgr.CodeToName(code) 112 | return stock_name, 0 113 | 114 | def get_current_cash(): 115 | """증거금 100% 주문 가능 금액을 반환한다.""" 116 | cpTradeUtil.TradeInit() 117 | acc = cpTradeUtil.AccountNumber[0] # 계좌번호 118 | accFlag = cpTradeUtil.GoodsList(acc, 1) # -1:전체, 1:주식, 2:선물/옵션 119 | cpCash.SetInputValue(0, acc) # 계좌번호 120 | cpCash.SetInputValue(1, accFlag[0]) # 상품구분 - 주식 상품 중 첫번째 121 | cpCash.BlockRequest() 122 | return cpCash.GetHeaderValue(9) # 증거금 100% 주문 가능 금액 123 | 124 | def get_target_price(code): 125 | """매수 목표가를 반환한다.""" 126 | try: 127 | time_now = datetime.now() 128 | str_today = time_now.strftime('%Y%m%d') 129 | ohlc = get_ohlc(code, 10) 130 | if str_today == str(ohlc.iloc[0].name): 131 | today_open = ohlc.iloc[0].open 132 | lastday = ohlc.iloc[1] 133 | else: 134 | lastday = ohlc.iloc[0] 135 | today_open = lastday[3] 136 | lastday_high = lastday[1] 137 | lastday_low = lastday[2] 138 | target_price = today_open + (lastday_high - lastday_low) * 0.5 139 | return target_price 140 | except Exception as ex: 141 | dbgout("`get_target_price() -> exception! " + str(ex) + "`") 142 | return None 143 | 144 | def get_movingaverage(code, window): 145 | """인자로 받은 종목에 대한 이동평균가격을 반환한다.""" 146 | try: 147 | time_now = datetime.now() 148 | str_today = time_now.strftime('%Y%m%d') 149 | ohlc = get_ohlc(code, 20) 150 | if str_today == str(ohlc.iloc[0].name): 151 | lastday = ohlc.iloc[1].name 152 | else: 153 | lastday = ohlc.iloc[0].name 154 | closes = ohlc['close'].sort_index() 155 | ma = closes.rolling(window=window).mean() 156 | return ma.loc[lastday] 157 | except Exception as ex: 158 | dbgout('get_movingavrg(' + str(window) + ') -> exception! ' + str(ex)) 159 | return None 160 | 161 | def buy_etf(code): 162 | """인자로 받은 종목을 최유리 지정가 FOK 조건으로 매수한다.""" 163 | try: 164 | global bought_list # 함수 내에서 값 변경을 하기 위해 global로 지정 165 | if code in bought_list: # 매수 완료 종목이면 더 이상 안 사도록 함수 종료 166 | #printlog('code:', code, 'in', bought_list) 167 | return False 168 | time_now = datetime.now() 169 | current_price, ask_price, bid_price = get_current_price(code) 170 | target_price = get_target_price(code) # 매수 목표가 171 | ma5_price = get_movingaverage(code, 5) # 5일 이동평균가 172 | ma10_price = get_movingaverage(code, 10) # 10일 이동평균가 173 | buy_qty = 0 # 매수할 수량 초기화 174 | if ask_price > 0: # 매도호가가 존재하면 175 | buy_qty = buy_amount // ask_price 176 | stock_name, stock_qty = get_stock_balance(code) # 종목명과 보유수량 조회 177 | #printlog('bought_list:', bought_list, 'len(bought_list):', 178 | # len(bought_list), 'target_buy_count:', target_buy_count) 179 | if current_price > target_price and current_price > ma5_price \ 180 | and current_price > ma10_price: 181 | printlog(stock_name + '(' + str(code) + ') ' + str(buy_qty) + 182 | 'EA : ' + str(current_price) + ' meets the buy condition!`') 183 | cpTradeUtil.TradeInit() 184 | acc = cpTradeUtil.AccountNumber[0] # 계좌번호 185 | accFlag = cpTradeUtil.GoodsList(acc, 1) # -1:전체,1:주식,2:선물/옵션 186 | # 최유리 FOK 매수 주문 설정 187 | cpOrder.SetInputValue(0, "2") # 2: 매수 188 | cpOrder.SetInputValue(1, acc) # 계좌번호 189 | cpOrder.SetInputValue(2, accFlag[0]) # 상품구분 - 주식 상품 중 첫번째 190 | cpOrder.SetInputValue(3, code) # 종목코드 191 | cpOrder.SetInputValue(4, buy_qty) # 매수할 수량 192 | cpOrder.SetInputValue(7, "2") # 주문조건 0:기본, 1:IOC, 2:FOK 193 | cpOrder.SetInputValue(8, "12") # 주문호가 1:보통, 3:시장가 194 | # 5:조건부, 12:최유리, 13:최우선 195 | # 매수 주문 요청 196 | ret = cpOrder.BlockRequest() 197 | printlog('최유리 FoK 매수 ->', stock_name, code, buy_qty, '->', ret) 198 | if ret == 4: 199 | remain_time = cpStatus.LimitRequestRemainTime 200 | printlog('주의: 연속 주문 제한에 걸림. 대기 시간:', remain_time/1000) 201 | time.sleep(remain_time/1000) 202 | return False 203 | time.sleep(2) 204 | printlog('현금주문 가능금액 :', buy_amount) 205 | stock_name, bought_qty = get_stock_balance(code) 206 | printlog('get_stock_balance :', stock_name, stock_qty) 207 | if bought_qty > 0: 208 | bought_list.append(code) 209 | dbgout("`buy_etf("+ str(stock_name) + ' : ' + str(code) + 210 | ") -> " + str(bought_qty) + "EA bought!" + "`") 211 | except Exception as ex: 212 | dbgout("`buy_etf("+ str(code) + ") -> exception! " + str(ex) + "`") 213 | 214 | def sell_all(): 215 | """보유한 모든 종목을 최유리 지정가 IOC 조건으로 매도한다.""" 216 | try: 217 | cpTradeUtil.TradeInit() 218 | acc = cpTradeUtil.AccountNumber[0] # 계좌번호 219 | accFlag = cpTradeUtil.GoodsList(acc, 1) # -1:전체, 1:주식, 2:선물/옵션 220 | while True: 221 | stocks = get_stock_balance('ALL') 222 | total_qty = 0 223 | for s in stocks: 224 | total_qty += s['qty'] 225 | if total_qty == 0: 226 | return True 227 | for s in stocks: 228 | if s['qty'] != 0: 229 | cpOrder.SetInputValue(0, "1") # 1:매도, 2:매수 230 | cpOrder.SetInputValue(1, acc) # 계좌번호 231 | cpOrder.SetInputValue(2, accFlag[0]) # 주식상품 중 첫번째 232 | cpOrder.SetInputValue(3, s['code']) # 종목코드 233 | cpOrder.SetInputValue(4, s['qty']) # 매도수량 234 | cpOrder.SetInputValue(7, "1") # 조건 0:기본, 1:IOC, 2:FOK 235 | cpOrder.SetInputValue(8, "12") # 호가 12:최유리, 13:최우선 236 | # 최유리 IOC 매도 주문 요청 237 | ret = cpOrder.BlockRequest() 238 | printlog('최유리 IOC 매도', s['code'], s['name'], s['qty'], 239 | '-> cpOrder.BlockRequest() -> returned', ret) 240 | if ret == 4: 241 | remain_time = cpStatus.LimitRequestRemainTime 242 | printlog('주의: 연속 주문 제한, 대기시간:', remain_time/1000) 243 | time.sleep(1) 244 | time.sleep(30) 245 | except Exception as ex: 246 | dbgout("sell_all() -> exception! " + str(ex)) 247 | 248 | if __name__ == '__main__': 249 | try: 250 | symbol_list = ['A122630', 'A252670', 'A233740', 'A250780', 'A225130', 251 | 'A280940', 'A261220', 'A217770', 'A295000', 'A176950'] 252 | bought_list = [] # 매수 완료된 종목 리스트 253 | target_buy_count = 5 # 매수할 종목 수 254 | buy_percent = 0.19 255 | printlog('check_creon_system() :', check_creon_system()) # 크레온 접속 점검 256 | stocks = get_stock_balance('ALL') # 보유한 모든 종목 조회 257 | total_cash = int(get_current_cash()) # 100% 증거금 주문 가능 금액 조회 258 | buy_amount = total_cash * buy_percent # 종목별 주문 금액 계산 259 | printlog('100% 증거금 주문 가능 금액 :', total_cash) 260 | printlog('종목별 주문 비율 :', buy_percent) 261 | printlog('종목별 주문 금액 :', buy_amount) 262 | printlog('시작 시간 :', datetime.now().strftime('%m/%d %H:%M:%S')) 263 | soldout = False; 264 | 265 | while True: 266 | t_now = datetime.now() 267 | t_9 = t_now.replace(hour=9, minute=0, second=0, microsecond=0) 268 | t_start = t_now.replace(hour=9, minute=5, second=0, microsecond=0) 269 | t_sell = t_now.replace(hour=15, minute=15, second=0, microsecond=0) 270 | t_exit = t_now.replace(hour=15, minute=20, second=0,microsecond=0) 271 | today = datetime.today().weekday() 272 | if today == 5 or today == 6: # 토요일이나 일요일이면 자동 종료 273 | printlog('Today is', 'Saturday.' if today == 5 else 'Sunday.') 274 | sys.exit(0) 275 | if t_9 < t_now < t_start and soldout == False: 276 | soldout = True 277 | sell_all() 278 | if t_start < t_now < t_sell : # AM 09:05 ~ PM 03:15 : 매수 279 | for sym in symbol_list: 280 | if len(bought_list) < target_buy_count: 281 | buy_etf(sym) 282 | time.sleep(1) 283 | if t_now.minute == 30 and 0 <= t_now.second <= 5: 284 | get_stock_balance('ALL') 285 | time.sleep(5) 286 | if t_sell < t_now < t_exit: # PM 03:15 ~ PM 03:20 : 일괄 매도 287 | if sell_all() == True: 288 | dbgout('`sell_all() returned True -> self-destructed!`') 289 | sys.exit(0) 290 | if t_exit < t_now: # PM 03:20 ~ :프로그램 종료 291 | dbgout('`self-destructed!`') 292 | sys.exit(0) 293 | time.sleep(3) 294 | except Exception as ex: 295 | dbgout('`main -> exception! ' + str(ex) + '`') 296 | 297 | -------------------------------------------------------------------------------- /08_Volatility_Breakout/imgs/NaverFinance_Naver.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/08_Volatility_Breakout/imgs/NaverFinance_Naver.jpg -------------------------------------------------------------------------------- /08_Volatility_Breakout/imgs/VB_ConfirmOrder.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/08_Volatility_Breakout/imgs/VB_ConfirmOrder.jpg -------------------------------------------------------------------------------- /08_Volatility_Breakout/imgs/VB_CreonBalance.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/08_Volatility_Breakout/imgs/VB_CreonBalance.jpg -------------------------------------------------------------------------------- /08_Volatility_Breakout/imgs/VB_CreonDownload.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/08_Volatility_Breakout/imgs/VB_CreonDownload.jpg -------------------------------------------------------------------------------- /08_Volatility_Breakout/imgs/VB_CreonPlusTray.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/08_Volatility_Breakout/imgs/VB_CreonPlusTray.jpg -------------------------------------------------------------------------------- /08_Volatility_Breakout/imgs/VB_CreonPlustLogin.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/08_Volatility_Breakout/imgs/VB_CreonPlustLogin.jpg -------------------------------------------------------------------------------- /08_Volatility_Breakout/imgs/VB_CurrentPrice.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/08_Volatility_Breakout/imgs/VB_CurrentPrice.jpg -------------------------------------------------------------------------------- /08_Volatility_Breakout/imgs/VB_EtfAlogTraderLog.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/08_Volatility_Breakout/imgs/VB_EtfAlogTraderLog.jpg -------------------------------------------------------------------------------- /08_Volatility_Breakout/imgs/VB_EtfSise.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/08_Volatility_Breakout/imgs/VB_EtfSise.jpg -------------------------------------------------------------------------------- /08_Volatility_Breakout/imgs/VB_HeadlessChrome.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/08_Volatility_Breakout/imgs/VB_HeadlessChrome.jpg -------------------------------------------------------------------------------- /08_Volatility_Breakout/imgs/VB_IdleAdmin.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/08_Volatility_Breakout/imgs/VB_IdleAdmin.jpg -------------------------------------------------------------------------------- /08_Volatility_Breakout/imgs/VB_JobExecute.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/08_Volatility_Breakout/imgs/VB_JobExecute.jpg -------------------------------------------------------------------------------- /08_Volatility_Breakout/imgs/VB_JobName.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/08_Volatility_Breakout/imgs/VB_JobName.jpg -------------------------------------------------------------------------------- /08_Volatility_Breakout/imgs/VB_JobOperation.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/08_Volatility_Breakout/imgs/VB_JobOperation.jpg -------------------------------------------------------------------------------- /08_Volatility_Breakout/imgs/VB_JobScheduler.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/08_Volatility_Breakout/imgs/VB_JobScheduler.jpg -------------------------------------------------------------------------------- /08_Volatility_Breakout/imgs/VB_JobTrigger.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/08_Volatility_Breakout/imgs/VB_JobTrigger.jpg -------------------------------------------------------------------------------- /08_Volatility_Breakout/imgs/VB_OHLC.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/08_Volatility_Breakout/imgs/VB_OHLC.jpg -------------------------------------------------------------------------------- /08_Volatility_Breakout/imgs/VB_PythonAdmin.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/08_Volatility_Breakout/imgs/VB_PythonAdmin.jpg -------------------------------------------------------------------------------- /08_Volatility_Breakout/imgs/VB_PythonwAdmin.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/08_Volatility_Breakout/imgs/VB_PythonwAdmin.jpg -------------------------------------------------------------------------------- /08_Volatility_Breakout/imgs/VB_SlackMessage.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/08_Volatility_Breakout/imgs/VB_SlackMessage.jpg -------------------------------------------------------------------------------- /08_Volatility_Breakout/imgs/VB_TigerHoga.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/08_Volatility_Breakout/imgs/VB_TigerHoga.jpg -------------------------------------------------------------------------------- /08_Volatility_Breakout/imgs/VB_TigerSise.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/08_Volatility_Breakout/imgs/VB_TigerSise.jpg -------------------------------------------------------------------------------- /08_Volatility_Breakout/imgs/VB_Trigger.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/08_Volatility_Breakout/imgs/VB_Trigger.jpg -------------------------------------------------------------------------------- /08_Volatility_Breakout/imgs/VB_VolatilityBreakout.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/08_Volatility_Breakout/imgs/VB_VolatilityBreakout.jpg -------------------------------------------------------------------------------- /08_Volatility_Breakout/imgs/VB_WinSearch.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/08_Volatility_Breakout/imgs/VB_WinSearch.jpg -------------------------------------------------------------------------------- /08_Volatility_Breakout/imgs/VolatilityBreakout.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/08_Volatility_Breakout/imgs/VolatilityBreakout.jpg -------------------------------------------------------------------------------- /08_Volatility_Breakout/imgs/yahoo_finance.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/08_Volatility_Breakout/imgs/yahoo_finance.jpg -------------------------------------------------------------------------------- /09_Deep_Learning_Prediction/ch09_01_StepFunction.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | 4 | def stepfunc(x): 5 | return np.where(x <= 0, 0, 1) 6 | 7 | x = np.arange(-10, 10, 0.1) 8 | y = stepfunc(x) 9 | 10 | plt.plot(x, y) 11 | plt.title('step function') 12 | plt.show() -------------------------------------------------------------------------------- /09_Deep_Learning_Prediction/ch09_02_SigmoidFunction.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | 4 | def sigmoid(x): 5 | return 1 / (1 + np.exp(-x)) 6 | 7 | x = np.arange(-10, 10, 0.1) 8 | y = sigmoid(x) 9 | 10 | plt.plot(x, y) 11 | plt.title('sigmoid function') 12 | plt.show() -------------------------------------------------------------------------------- /09_Deep_Learning_Prediction/ch09_03_TanhFunction.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | 4 | def tanh(x): 5 | return (np.exp(x) - np.exp(-x)) / (np.exp(x) + np.exp(-x)) 6 | 7 | x = np.arange(-10, 10, 0.1) 8 | y = tanh(x) 9 | 10 | plt.plot(x, y) 11 | plt.title('tanh function') 12 | plt.show() 13 | -------------------------------------------------------------------------------- /09_Deep_Learning_Prediction/ch09_04_ReLUFunction.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | 4 | def relu(x): 5 | return np.maximum(0, x) 6 | 7 | x = np.arange(-10, 10, 0.1) 8 | y = relu(x) 9 | 10 | plt.plot(x, y) 11 | plt.title('ReLU function') 12 | plt.show() -------------------------------------------------------------------------------- /09_Deep_Learning_Prediction/ch09_05_SoftmaxFunction.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | 4 | def softmax(x): 5 | return np.exp(x) / np.sum(np.exp(x)) -------------------------------------------------------------------------------- /09_Deep_Learning_Prediction/ch09_06_MLP_HiddenLayer.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | X = np.array([10, 20]) # ① 3 | W1 = np.array([[0.1, 0.3, 0.5], [0.2, 0.4, 0.6]]) 4 | B1 = np.array([1, 2, 3]) # ③ 5 | 6 | def sigmoid(x): 7 | return 1 / (1 + np.exp(-x)) 8 | 9 | A1 = np.dot(X, W1) + B1 10 | Z1 = sigmoid(A1) 11 | 12 | print('A1 :', A1) 13 | print('Z1 :', Z1) -------------------------------------------------------------------------------- /09_Deep_Learning_Prediction/ch09_07_MLP_OutputLayer.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | X = np.array([10, 20]) # ① 3 | W1 = np.array([[0.1, 0.3, 0.5], [0.2, 0.4, 0.6]]) 4 | B1 = np.array([1, 2, 3]) # ③ 5 | 6 | def sigmoid(x): 7 | return 1 / (1 + np.exp(-x)) 8 | 9 | A1 = np.dot(X, W1) + B1 10 | Z1 = sigmoid(A1) 11 | 12 | W2 = np.array([[0.1, 0.4], [0.2, 0.5], [0.3, 0.6]]) 13 | B2 = np.array([0.1, 0.2]) 14 | 15 | A2 = np.dot(Z1, W2) + B2 16 | Y = sigmoid(A2) 17 | 18 | print('A2 :', A2) 19 | print('Y :', Y) 20 | -------------------------------------------------------------------------------- /09_Deep_Learning_Prediction/ch09_08_LinearRegression.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pylab as plt 2 | import tensorflow as tf 3 | 4 | x_data = [1, 2, 3, 4, 5] 5 | y_data = [2, 3, 4, 5, 6] 6 | 7 | w = tf.Variable(0.7) 8 | b = tf.Variable(0.7) 9 | learn_rate = 0.01 10 | 11 | print(f'step| w| b| cost') 12 | print(f'----|-----|-----|-----') 13 | 14 | for i in range(1, 1101): 15 | with tf.GradientTape() as tape: 16 | hypothesis = w * x_data + b 17 | cost = tf.reduce_mean((hypothesis - y_data)**2) # tf.losses.mean_squared_error(y, y_hat) 18 | dw, db = tape.gradient(cost, [w, b]) 19 | w.assign_sub(learn_rate * dw) # a = a - b 20 | b.assign_sub(learn_rate * db) 21 | 22 | if i in [1, 3, 5, 10, 1000, 1100]: 23 | print(f"{i:4d}| {w.numpy():.2f}| {b.numpy():.2f}| {cost:.2f}") 24 | plt.figure(figsize=(7, 7)) 25 | plt.title(f'[Step {i:d}] h(x) = { w.numpy():.2f}x + {b.numpy():.2f}') 26 | plt.plot(x_data, y_data, 'o') # ⑥ 27 | plt.plot(x_data, w * x_data + b, 'r', label='hypothesis') # ⑦ 28 | plt.xlabel('x_data') 29 | plt.ylabel('y_data') 30 | plt.xlim(0, 6) 31 | plt.ylim(1, 7) 32 | plt.legend(loc='best') 33 | plt.show() 34 | 35 | -------------------------------------------------------------------------------- /09_Deep_Learning_Prediction/ch09_09_RNN_StockPrediction.py: -------------------------------------------------------------------------------- 1 | from tensorflow.keras import Sequential 2 | from tensorflow.keras.layers import Dense, LSTM, Dropout 3 | import numpy as np 4 | import matplotlib.pyplot as plt 5 | from Investar import Analyzer 6 | 7 | mk = Analyzer.MarketDB() 8 | raw_df = mk.get_daily_price('삼성전자', '2018-05-04', '2020-01-22') 9 | 10 | window_size = 10 11 | data_size = 5 12 | 13 | def MinMaxScaler(data): 14 | """최솟값과 최댓값을 이용하여 0 ~ 1 값으로 변환""" 15 | numerator = data - np.min(data, 0) 16 | denominator = np.max(data, 0) - np.min(data, 0) 17 | # 0으로 나누기 에러가 발생하지 않도록 매우 작은 값(1e-7)을 더해서 나눔 18 | return numerator / (denominator + 1e-7) 19 | 20 | dfx = raw_df[['open','high','low','volume', 'close']] 21 | dfx = MinMaxScaler(dfx) 22 | dfy = dfx[['close']] 23 | 24 | x = dfx.values.tolist() 25 | y = dfy.values.tolist() 26 | 27 | data_x = [] 28 | data_y = [] 29 | for i in range(len(y) - window_size): 30 | _x = x[i : i + window_size] # 다음 날 종가(i+windows_size)는 포함되지 않음 31 | _y = y[i + window_size] # 다음 날 종가 32 | data_x.append(_x) 33 | data_y.append(_y) 34 | print(_x, "->", _y) 35 | 36 | train_size = int(len(data_y) * 0.7) 37 | train_x = np.array(data_x[0 : train_size]) 38 | train_y = np.array(data_y[0 : train_size]) 39 | 40 | test_size = len(data_y) - train_size 41 | test_x = np.array(data_x[train_size : len(data_x)]) 42 | test_y = np.array(data_y[train_size : len(data_y)]) 43 | 44 | # 모델 생성 45 | model = Sequential() 46 | model.add(LSTM(units=10, activation='relu', return_sequences=True, input_shape=(window_size, data_size))) 47 | model.add(Dropout(0.1)) 48 | model.add(LSTM(units=10, activation='relu')) 49 | model.add(Dropout(0.1)) 50 | model.add(Dense(units=1)) 51 | model.summary() 52 | 53 | model.compile(optimizer='adam', loss='mean_squared_error') 54 | model.fit(train_x, train_y, epochs=60, batch_size=30) 55 | pred_y = model.predict(test_x) 56 | 57 | # Visualising the results 58 | plt.figure() 59 | plt.plot(test_y, color='red', label='real SEC stock price') 60 | plt.plot(pred_y, color='blue', label='predicted SEC stock price') 61 | plt.title('SEC stock price prediction') 62 | plt.xlabel('time') 63 | plt.ylabel('stock price') 64 | plt.legend() 65 | plt.show() 66 | 67 | # raw_df.close[-1] : dfy.close[-1] = x : pred_y[-1] 68 | print("Tomorrow's SEC price :", raw_df.close[-1] * pred_y[-1] / dfy.close[-1], 'KRW') 69 | 70 | -------------------------------------------------------------------------------- /09_Deep_Learning_Prediction/imgs/AI_Difference.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/09_Deep_Learning_Prediction/imgs/AI_Difference.jpg -------------------------------------------------------------------------------- /09_Deep_Learning_Prediction/imgs/AI_LR_Step1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/09_Deep_Learning_Prediction/imgs/AI_LR_Step1.jpg -------------------------------------------------------------------------------- /09_Deep_Learning_Prediction/imgs/AI_LR_Step2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/09_Deep_Learning_Prediction/imgs/AI_LR_Step2.jpg -------------------------------------------------------------------------------- /09_Deep_Learning_Prediction/imgs/AI_LR_Step3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/09_Deep_Learning_Prediction/imgs/AI_LR_Step3.jpg -------------------------------------------------------------------------------- /09_Deep_Learning_Prediction/imgs/AI_LR_Step4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/09_Deep_Learning_Prediction/imgs/AI_LR_Step4.jpg -------------------------------------------------------------------------------- /09_Deep_Learning_Prediction/imgs/AI_LR_Step5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/09_Deep_Learning_Prediction/imgs/AI_LR_Step5.jpg -------------------------------------------------------------------------------- /09_Deep_Learning_Prediction/imgs/AI_LR_Step6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/09_Deep_Learning_Prediction/imgs/AI_LR_Step6.jpg -------------------------------------------------------------------------------- /09_Deep_Learning_Prediction/imgs/AI_LTSM1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/09_Deep_Learning_Prediction/imgs/AI_LTSM1.jpg -------------------------------------------------------------------------------- /09_Deep_Learning_Prediction/imgs/AI_LTSM2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/09_Deep_Learning_Prediction/imgs/AI_LTSM2.jpg -------------------------------------------------------------------------------- /09_Deep_Learning_Prediction/imgs/AI_MLP.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/09_Deep_Learning_Prediction/imgs/AI_MLP.jpg -------------------------------------------------------------------------------- /09_Deep_Learning_Prediction/imgs/AI_PerceptronImage.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/09_Deep_Learning_Prediction/imgs/AI_PerceptronImage.jpg -------------------------------------------------------------------------------- /09_Deep_Learning_Prediction/imgs/AI_RNN.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/09_Deep_Learning_Prediction/imgs/AI_RNN.jpg -------------------------------------------------------------------------------- /09_Deep_Learning_Prediction/imgs/AI_ReLUFunc.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/09_Deep_Learning_Prediction/imgs/AI_ReLUFunc.jpg -------------------------------------------------------------------------------- /09_Deep_Learning_Prediction/imgs/AI_SigmoidFunc.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/09_Deep_Learning_Prediction/imgs/AI_SigmoidFunc.jpg -------------------------------------------------------------------------------- /09_Deep_Learning_Prediction/imgs/AI_StepFunc.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/09_Deep_Learning_Prediction/imgs/AI_StepFunc.jpg -------------------------------------------------------------------------------- /09_Deep_Learning_Prediction/imgs/AI_StockPricePrediction.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/09_Deep_Learning_Prediction/imgs/AI_StockPricePrediction.jpg -------------------------------------------------------------------------------- /09_Deep_Learning_Prediction/imgs/AI_StockPricePrediction_Cmd.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/09_Deep_Learning_Prediction/imgs/AI_StockPricePrediction_Cmd.jpg -------------------------------------------------------------------------------- /09_Deep_Learning_Prediction/imgs/AI_TanhFunc.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/09_Deep_Learning_Prediction/imgs/AI_TanhFunc.jpg -------------------------------------------------------------------------------- /10_Appendix_(Python_Built-in_Functions_and_AES-256_Encryption).pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/10_Appendix_(Python_Built-in_Functions_and_AES-256_Encryption).pdf -------------------------------------------------------------------------------- /PowerPoint_Materials.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/INVESTAR/StockAnalysisInPython/e356b8fd80fcc48ef666d5f7bffcc22ae2ad66f4/PowerPoint_Materials.pptx -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 파이썬 증권 데이터 분석 (Stock Analysis in Python) 2 | 본 깃허브에서는 『파이썬 증권 데이터 분석』(한빛출판사, 2020) 서적과 관련된 소스 코드와 추가 자료를 공유합니다. 3 | 4 | - 소스 코드는 각 장별 디렉터리에 존재하며, 이미지 파일들은 각 장별로 imgs 디렉터리에 존재합니다. 5 | 6 | - 114 페이지 소스코드의 이미지 파일 URL은 http://bit.ly/2JnsHnT → http://bit.ly/3ZZyeXQ 변경됐습니다. 7 | 8 | - 지면 관계 상 싣지 못한 파이썬 내장함수표와 AES-256 암복호화 실습은 9 | 10_Appendix_(Python_Built-in_Functions_and_AES-256_Encryption).pdf 파일을 참고하시기 바랍니다. 10 | 11 | - 서적에 삽입된 그림의 PPT 원본은 PowerPoint_Materials.pptx 파일에 있습니다. 12 | 13 | ## 네이버 일별시세 전일비 데이터 변경에 따른 DBUpdaterEx 수정 내역 14 | 네이버 일별시세의 전일비 데이터가 기존에는 숫자로만 제공되었으나, 전일비 데이터에 상승/하락/보합 등의 문자열이 추가되면서 아래처럼 Exception이 발생하는 현상이 있었습니다. 15 | ![ExceptionOccured_2024-06-30](./05_Stock_Price_API/imgs/ExceptionOccured_2024-06-30.jpg) 16 | 17 | 전일비 데이터(diff)에서 문자를 제외하고 숫자만 추출하도록 DBUpdaterEx.py에 아래처럼 코드 한 줄을 추가하였습니다. (2024-06-30 기준) 18 | ![DBUpdaterEx_2024-06-30](./05_Stock_Price_API/imgs/DBUpdaterEx_2024-06-30.jpg) 19 | 20 | ## 시세조회 DB 업데이트 및 시세조회 API 빠른 사용법 21 | 책이 출간된지 제법 시간이 흘렀고 파이썬 라이브러리에도 변경된 내용이 많아서 최신 라이브러리 간 호환성이 확보되지 않을 수 있습니다. 시세조회 DB를 빠르게 구축해서 시세조회 API를 사용하고자 하시는 분은 아래처럼 requirements.txt에 명시된 라이브러리 버전으로 설치하시 바랍니다. (2024-03-03 기준) 22 | 1. Python 설치 23 | ① Win+R키를 눌러서 실행창이 나오면 appwiz.cpl를 입력한 후 '프로그램 변경 및 제거' 창에서 기존에 설치된 Python을 전부 제거 24 | ② https://www.python.org/ftp/python/3.8.1/python-3.8.1-amd64.exe 다운로드 25 | ③ 설치 프로그램을 실행한 후 'Add Python 3.8 to PATH' 체크박스에 체크한 후 'Install Now'로 설치 26 | ④ Python 설치가 완료되면 명령창을 새로 실행해서 python --version 명령으로 Python 3.8.1이 설치됐는지 확인 27 | 2. Python 라이브러리 설치 28 | ① https://github.com/INVESTAR/StockAnalysisInPython/blob/master/02_Python_Programming/requirements.txt 다운로드 29 | ② c:\Users\hwang\Downloads>python -m pip install --upgrade pip 30 | ③ c:\Users\hwang\Downloads>pip install -r requirements.txt 31 | 3. Investar 데이터베이스 생성 32 | ① https://mariadb.com/downloads/ 접속 33 | ② MariaDB Community -> Windows 64bit -> 10.5.24GA 다운로드해서 실행 34 | ③ 바탕화면에 생성된 HediSQL 아이콘을 더블 클릭하여 실행한 후 Investar DB를 utf8_general_ci 로 생성 35 | ![HeidiSQL](./05_Stock_Price_API/imgs/HeidiSQL.png) 36 | ④ 쿼리 탭을 클릭해서 테이블 생성 쿼리를 실행 37 | CREATE TABLE IF NOT EXISTS company_info ( 38 | code VARCHAR(20), 39 | company VARCHAR(40), 40 | last_update DATE, 41 | PRIMARY KEY (code) 42 | ); 43 | CREATE TABLE IF NOT EXISTS daily_price ( 44 | code VARCHAR(20), 45 | date DATE, 46 | open BIGINT(20), 47 | high BIGINT(20), 48 | low BIGINT(20), 49 | close BIGINT(20), 50 | diff BIGINT(20), 51 | volume BIGINT(20), 52 | PRIMARY KEY (code, date) 53 | ); 54 | 5. myPackage 생성 및 API 호출 55 | ① c:\myPackage\Investar 폴더를 생성 56 | ② https://github.com/INVESTAR/StockAnalysisInPython/tree/master/05_Stock_Price_API/Investar 폴더로부터 Analyzer.py, DBUpdaterEx.py, MarketDB.py를 다운로드 받아서 c:\myPackage\Investar 폴더로 복사 57 | ③ c:\myPackage\Investar>python DBUpdaterEx.py 실행해서 데이터베이스를 업데이트 58 | ![DBUpdaterEx2024-03-03](./05_Stock_Price_API/imgs/DBUpdaterEx2024-03-03.png) 59 | ④ IDLE에서 c:\myPackage\Invesat\Analyzer.py 파일을 실행한 뒤 아래처럼 API 호출 60 | ![GetDailyPrice](./05_Stock_Price_API/imgs/GetDailyPrice.png) 61 | 62 | ## 네이버 금융의 웹 스크레이핑 차단에 대한 안내 63 | 아래 내용은 2021년 10월 11일에 발행된 5쇄 서적부터 반영되어 있으며, 64 | 기존에 발행된 1쇄~4쇄 서적을 구매하신 분들은 아래 내용을 참고하시기 바랍니다. 65 | 66 | 2021년 1월 7일 저녁부터 네이버 금융에서 웹 크롤러의 스크레이핑을 차단하기 시작했습니다. 67 | 따라서 기존 방식대로 urllib.request.urlopen()이나 pandas.read_html()를 사용할 경우, 68 | 더 이상 네이버 금융의 웹 페이지를 읽어올 수 없습니다. 69 | 70 | 네이버 금융 서버에서 http 패킷 헤더의 웹 브라우저 정보(User-Agent)를 체크하기 때문에, 71 | 웹 스크레이핑을 하려면 requests 라이브러리를 이용해 웹 브라우저 정보를 보내야 합니다. 72 | 변경된 코드는 아래와 같으며 DBUpdaterEx.py로 깃헙에 올려두었습니다. 73 | 74 | ![DBUpdaterEx](./05_Stock_Price_API/imgs/DBUpdaterEx.jpg) 75 | 76 | http://httpbin.org/user-agent 사이트에 접속하시면 77 | 현재 본인이 사용하는 웹 브라우저에 대한 정보를 확인할 수 있습니다. 78 | 샘플 코드의 "Mozilla/5.0"를 실제로 본인이 사용하는 웹 브라우저 정보로 변경하면 79 | 네이버 금융 페이지에서 차단될 가능성을 조금 더 줄일 수 있습니다. 80 | --------------------------------------------------------------------------------