장유진

종목 선별 및 백테스팅 프로그램 최종본

Showing 46 changed files with 241 additions and 300 deletions
1 -# Default ignored files
2 -/shelf/
3 -/workspace.xml
4 -# Datasource local storage ignored files
5 -/../../../../../../../:\Users\YuJin\Desktop\캡디2\stock_pbr_test\.idea/dataSources/
6 -/dataSources.local.xml
7 -# Editor-based HTTP Client requests
8 -/httpRequests/
1 -<?xml version="1.0" encoding="UTF-8"?>
2 -<project version="4">
3 - <component name="Encoding">
4 - <file url="file://$PROJECT_DIR$/result_kr.csv" charset="x-windows-949" />
5 - <file url="file://$PROJECT_DIR$/result_kr1.csv" charset="x-windows-949" />
6 - </component>
7 -</project>
...\ No newline at end of file ...\ No newline at end of file
1 -from Investment.Strategy.StrategyBase import StrategyBase
2 -from Investment.Strategy.FinancialStatementsStrategyBase import FinancialStatementsStrategyBase
3 -from datetime import date
4 -
5 -
6 -class Strategy(FinancialStatementsStrategyBase):
7 - def __init__(self):
8 - super().__init__()
9 -
10 - def __repr__(self):
11 - return self.Name
12 -
13 - def setStrategy(self, per=None, pbr_up=None, pbr_down=None, roe=None, order='PER'):
14 - super().setStrategy()
15 - self.Name = 'PER_ROE_V1.0'
16 - self.NumberOfStocks = 10
17 - self.AdditionalFinancialStatementsItem = ['PER', 'PBR', 'ROE']
18 - # self.FinancialStatementsCondition = '(PER > 6) and (ROE > 10) and (PBR > 0.5) and (PBR < 1)'
19 - self.setFinancialStatementsCondition(per, pbr_up, pbr_down, roe)
20 - print(self.FinancialStatementsCondition)
21 - # self.FinancialStatementsCondition = '(PER > 0) and (PER < 20) and (ROE > 10)'
22 - # self.FinancialStatementsCondition = '(PBR < 1)'
23 - self.FinancialStatementsYear = 2016
24 - self.FinancialStatementsQuater = 4
25 - self.FinancialStatementsDiv = 'CFS'
26 - self.StockDate = date(2017, 4, 10)
27 - self.FinancialStatementsSearchTarget = ['StockCode', 'Equity', 'ProfitLoss']
28 - self.StockSearchTarget = ['MarketCapitalization']
29 - self.FinancialStatementsOrderBy = [order]
30 - if order == 'PER':
31 - self.FinancialStatementsOrderMethod = 'asc'
32 - else:
33 - self.FinancialStatementsOrderMethod = 'desc'
34 - # self.FinancialStatementsOrderBy.append('ROE')
35 - # self.FinancialStatementsOrderMethod = 'desc'
36 -
37 - def setFinancialStatementsCondition(self, per, pbr_up, pbr_down, roe):
38 - self.FinancialStatementsCondition = ''
39 - if per is not None:
40 - self.FinancialStatementsCondition += f'(PER > {per})'
41 - if pbr_up:
42 - if len(self.FinancialStatementsCondition) == 0:
43 - self.FinancialStatementsCondition += f'(PBR > {pbr_up})'
44 - else:
45 - self.FinancialStatementsCondition += f' and (PBR > {pbr_up})'
46 - if pbr_down:
47 - if len(self.FinancialStatementsCondition) == 0:
48 - self.FinancialStatementsCondition += f'(PBR < {pbr_down})'
49 - else:
50 - self.FinancialStatementsCondition += f' and (PBR < {pbr_down})'
51 - if roe:
52 - if len(self.FinancialStatementsCondition) == 0:
53 - self.FinancialStatementsCondition += f'(ROE > {roe})'
54 - else:
55 - self.FinancialStatementsCondition += f' and (ROE > {roe})'
56 -
57 - def searchData(self):
58 - return FinancialStatementsStrategyBase.searchData(self)
59 -
60 - def setAdditionalData(self):
61 - return FinancialStatementsStrategyBase.setAdditionalData(self)
1 -import datetime
2 -import Strategy
3 -import Trading
4 -import Verification
5 -import sys
6 -import DataProvider
7 -
8 -
9 -def single():
10 - record = [0]
11 - # record = [18.91309, 17.8967, 17.14154, 16.07653, 16.03074]
12 - strategy_record = [[3, 0.7000000000000001, 10, 18.91309], [3, 0.7000000000000001, 11, 17.8967],
13 - [3, 0.8, 11, 17.14154], [4, 0.7000000000000001, 11, 16.07653],
14 - [3, 0.7000000000000001, 5, 16.03074]]
15 - st = Strategy.Strategy()
16 - tr = Trading.Trading()
17 - ve = Verification.Verification()
18 - db = DataProvider.DataProvider()
19 - if db.initialize():
20 - print('db connection')
21 - # print(db.findSP(['StockDate','Open'], '004990', '2019-04-11', '2019-12-31'))
22 - st.db = db
23 - st.setStrategy(10, 0, 1.5, 0)
24 - if (st.searchData() == False):
25 - print("st.searchData error")
26 - sys.exit(-1)
27 - if (st.setAdditionalData() == False):
28 - print("st.setAdditionalData error")
29 - sys.exit(-1)
30 -
31 - tr.df_all = st.df_all
32 - tr.db = db
33 - tr.setTrading()
34 - if (tr.doTrading() == False):
35 - print("tr.doTrading error")
36 - sys.exit(-1)
37 -
38 - ve.TotalInvestmentAmount = tr.TotalInvestmentAmount
39 - ve.df_all = tr.df_all
40 -
41 - ve.setVerification()
42 - ve.doVerification()
43 - ve.saveResult()
44 - # ve.saveResulToJSON()
45 - r, Yield = ve.saveSummary(record, 0)
46 - else:
47 - print("db error")
48 - db.close()
49 -
50 -
51 -def multi():
52 - start = datetime.datetime.now()
53 - record = [0]
54 - strategy_record = [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
55 - num = 0
56 - st = Strategy.Strategy()
57 - tr = Trading.Trading()
58 - ve = Verification.Verification()
59 - db = DataProvider.DataProvider()
60 - for per in range(8):
61 - pbr = 1
62 - while pbr > 0.3:
63 - for roe in range(10, 20):
64 - if db.initialize():
65 - print('db connection')
66 - # print(db.findSP(['StockDate','Open'], '004990', '2019-04-11', '2019-12-31'))
67 - st.db = db
68 - else:
69 - print("db error")
70 - st.setStrategy(per, pbr, 1.2, roe)
71 - if (st.searchData() == False):
72 - print("st.searchData error")
73 - sys.exit(-1)
74 - if (st.setAdditionalData() == False):
75 - print("st.setAdditionalData error")
76 - sys.exit(-1)
77 -
78 - tr.df_all = st.df_all
79 - tr.db = db
80 - tr.setTrading()
81 - if (tr.doTrading() == False):
82 - print("tr.doTrading error")
83 - sys.exit(-1)
84 -
85 - ve.TotalInvestmentAmount = tr.TotalInvestmentAmount
86 - ve.df_all = tr.df_all
87 - ve.setVerification()
88 - ve.doVerification()
89 - ve.saveResult()
90 - # ve.saveResulToJSON()
91 - r, Yield = ve.saveSummary(record, num)
92 - if r:
93 - for i in range(5):
94 - if strategy_record[i][3] < Yield:
95 - strategy_record.insert(i, [per, pbr, roe, Yield])
96 - break
97 - strategy_record.pop()
98 - print(record, strategy_record)
99 - num += 1
100 - pbr -= 0.1
101 - db.close()
102 - end = datetime.datetime.now()
103 - print('time: ', end - start)
104 - print(strategy_record)
105 -
106 -
107 -if __name__ == '__main__':
108 - single()
109 - # multi()
1 -,StockCode,StockName,Equity,ProfitLoss,PER,MarketCapitalization,PBR,BuyingPrice,SellPrice,BuyingAmount,ProfitLossByStock,InvestmentAmount,Balance,Yield
2 -0,002030,아세아,1225090202229.0,67565442549.0,3.171475522336699,214282147200.0,0.17491132229294026,97800.0,125000.0,102.0,27200.0,9975600.0,12750000.0,27.811860940695297
3 -1,058650,세아홀딩스,2924149208280.0,161892654956.0,3.1872971639154417,516000000000.0,0.17646158360828446,126000.0,133500.0,79.0,7500.0,9954000.0,10546500.0,5.952380952380952
4 -2,001940,KISCO홀딩스,1273968329992.0,77864434261.0,2.956621941518533,230215694800.0,0.18070754930104554,63000.0,65300.0,158.0,2300.0,9954000.0,10317400.0,3.650793650793651
5 -3,000880,한화,14227936000000.0,1288691000000.0,2.0445549284118534,2634799535250.0,0.1851849442709048,35700.0,38350.0,280.0,2650.0,9996000.0,10738000.0,7.42296918767507
6 -4,007860,서연,1072030023657.0,132366474007.0,1.7827205413624674,235972432200.0,0.22011737264132844,10150.0,6480.0,985.0,-3670.0,9997750.0,6382800.0,-36.1576354679803
7 -5,019010,베뉴지,236756098347.0,12783309005.0,4.769735283419287,60973000000.0,0.25753507692391236,12850.0,12800.0,778.0,-50.0,9997300.0,9958400.0,-0.38910505836575876
8 -6,092230,KPX홀딩스,936238978408.0,53425479418.0,4.894772873332309,261505587400.0,0.2793149969516004,63000.0,63000.0,158.0,0.0,9954000.0,9954000.0,0.0
9 -7,023600,삼보판지,329937058742.0,40288485800.0,2.380332695452158,95900000000.0,0.29066149878904834,6860.0,9790.0,1457.0,2930.0,9995020.0,14264030.0,42.711370262390666
10 -8,033160,엠케이전자,593852198159.0,74507668124.0,2.391281644105155,178168819130.0,0.30002215986122605,8360.0,10250.0,1196.0,1890.0,9998560.0,12259000.0,22.607655502392344
11 -9,021820,세원정공,569620475934.0,56809840064.0,3.309285852384124,188000000000.0,0.3300443153693494,18350.0,13700.0,544.0,-4650.0,9982400.0,7452800.0,-25.340599455040874
12 -10,,,,,,,,,,,,,104622930.0,4.8183
1 -,StockCode,StockName,Equity,ProfitLoss,PER,MarketCapitalization,PBR,ROE,BuyingPrice,SellPrice,BuyingAmount,ProfitLossByStock,InvestmentAmount,Balance,Yield
2 -0,008370,원풍,75070172618.0,5235935528.0,10.049779971240318,52620000000.0,0.7009441721648979,6.974721577694294,4505.0,4050.0,2219.0,-455.0,9996595.0,8986950.0,-10.099889012208656
3 -1,119860,다나와,65170505380.0,8935066130.0,10.052978437217229,89824027140.0,1.378292628179708,13.71029130110453,6930.0,17950.0,1443.0,11020.0,9999990.0,25901850.0,159.01875901875903
4 -2,014970,삼륭물산,65649138867.0,9219435245.0,10.073013968004718,92867500000.0,1.4146034754262697,14.043497605776448,6470.0,5500.0,1545.0,-970.0,9996150.0,8497500.0,-14.992272024729521
5 -3,004430,송원산업,354189000000.0,42244000000.0,10.084272322696714,426000000000.0,1.2027476855577106,11.926965546643178,18500.0,29150.0,540.0,10650.0,9990000.0,15741000.0,57.567567567567565
6 -4,017040,광명전기,98063359627.0,11593891042.0,10.111208407111059,117228248575.0,1.1954337381555842,11.822857269115863,2800.0,3620.0,3571.0,820.0,9998800.0,12927020.0,29.28571428571429
7 -5,027710,팜스토리,166916854808.0,12896142588.0,10.173269575747343,131195935035.0,0.7859957293462735,7.726087699671845,1515.0,1300.0,6600.0,-215.0,9999000.0,8580000.0,-14.19141914191419
8 -6,069510,에스텍,124146823459.0,14748421661.0,10.208414395835193,150558000000.0,1.2127414605152778,11.879822012418003,14150.0,10800.0,706.0,-3350.0,9989900.0,7624800.0,-23.674911660777383
9 -7,012200,계양전기,179133111299.0,17233731189.0,10.214851216454122,176040000000.0,0.9827328890981124,9.620628516988308,5500.0,4140.0,1818.0,-1360.0,9999000.0,7526520.0,-24.727272727272727
10 -8,204320,만도,1515053750297.0,210079641643.0,10.237241834478636,2150636096000.0,1.4195114170559329,13.866151059117046,231500.0,231000.0,43.0,-500.0,9954500.0,9933000.0,-0.21598272138228944
11 -9,098660,에스티오,33858491829.0,3213669838.0,10.254857832723014,32955727310.0,0.9733371313890958,9.491473672927961,3865.0,2820.0,2587.0,-1045.0,9998755.0,7295340.0,-27.037516170763258
12 -10,,,,,,,,,,,,,,113013980.0,13.09129
...@@ -4,6 +4,13 @@ ...@@ -4,6 +4,13 @@
4 <inspection_tool class="PyChainedComparisonsInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true"> 4 <inspection_tool class="PyChainedComparisonsInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
5 <option name="ignoreConstantInTheMiddle" value="true" /> 5 <option name="ignoreConstantInTheMiddle" value="true" />
6 </inspection_tool> 6 </inspection_tool>
7 + <inspection_tool class="PyPep8NamingInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
8 + <option name="ignoredErrors">
9 + <list>
10 + <option value="N802" />
11 + </list>
12 + </option>
13 + </inspection_tool>
7 <inspection_tool class="PyUnresolvedReferencesInspection" enabled="true" level="WARNING" enabled_by_default="true"> 14 <inspection_tool class="PyUnresolvedReferencesInspection" enabled="true" level="WARNING" enabled_by_default="true">
8 <option name="ignoredIdentifiers"> 15 <option name="ignoredIdentifiers">
9 <list> 16 <list>
......
1 <?xml version="1.0" encoding="UTF-8"?> 1 <?xml version="1.0" encoding="UTF-8"?>
2 <project version="4"> 2 <project version="4">
3 - <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.9 (stock_pbr_test)" project-jdk-type="Python SDK" /> 3 + <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.9 (stock_pbr_test (1))" project-jdk-type="Python SDK" />
4 </project> 4 </project>
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
2 <project version="4"> 2 <project version="4">
3 <component name="ProjectModuleManager"> 3 <component name="ProjectModuleManager">
4 <modules> 4 <modules>
5 - <module fileurl="file://$PROJECT_DIR$/.idea/stock_pbr_test.iml" filepath="$PROJECT_DIR$/.idea/stock_pbr_test.iml" /> 5 + <module fileurl="file://$PROJECT_DIR$/.idea/stock_pbr_test (1).iml" filepath="$PROJECT_DIR$/.idea/stock_pbr_test (1).iml" />
6 </modules> 6 </modules>
7 </component> 7 </component>
8 </project> 8 </project>
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
4 <content url="file://$MODULE_DIR$"> 4 <content url="file://$MODULE_DIR$">
5 <excludeFolder url="file://$MODULE_DIR$/venv" /> 5 <excludeFolder url="file://$MODULE_DIR$/venv" />
6 </content> 6 </content>
7 - <orderEntry type="jdk" jdkName="Python 3.9 (stock_pbr_test)" jdkType="Python SDK" /> 7 + <orderEntry type="jdk" jdkName="Python 3.9 (stock_pbr_test (1))" jdkType="Python SDK" />
8 <orderEntry type="sourceFolder" forTests="false" /> 8 <orderEntry type="sourceFolder" forTests="false" />
9 </component> 9 </component>
10 </module> 10 </module>
...\ No newline at end of file ...\ No newline at end of file
......
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<project version="4">
3 + <component name="ChangeListManager">
4 + <list default="true" id="08cfd845-d1af-47c5-9eaf-7ec10bc089e6" name="Default Changelist" comment="" />
5 + <option name="SHOW_DIALOG" value="false" />
6 + <option name="HIGHLIGHT_CONFLICTS" value="true" />
7 + <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
8 + <option name="LAST_RESOLUTION" value="IGNORE" />
9 + </component>
10 + <component name="GitSEFilterConfiguration">
11 + <file-type-list>
12 + <filtered-out-file-type name="LOCAL_BRANCH" />
13 + <filtered-out-file-type name="REMOTE_BRANCH" />
14 + <filtered-out-file-type name="TAG" />
15 + <filtered-out-file-type name="COMMIT_BY_MESSAGE" />
16 + </file-type-list>
17 + </component>
18 + <component name="ProjectId" id="1rhNXDA6G2BEILfU2FcLF2UeeII" />
19 + <component name="ProjectViewState">
20 + <option name="hideEmptyMiddlePackages" value="true" />
21 + <option name="showLibraryContents" value="true" />
22 + </component>
23 + <component name="PropertiesComponent">
24 + <property name="RunOnceActivity.OpenProjectViewOnStart" value="true" />
25 + <property name="RunOnceActivity.ShowReadmeOnStart" value="true" />
26 + <property name="WebServerToolWindowFactoryState" value="false" />
27 + <property name="last_opened_file_path" value="$PROJECT_DIR$/../stock_pbr_test" />
28 + <property name="settings.editor.selected.configurable" value="com.jetbrains.python.configuration.PyActiveSdkModuleConfigurable" />
29 + </component>
30 + <component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
31 + <component name="TaskManager">
32 + <task active="true" id="Default" summary="Default task">
33 + <changelist id="08cfd845-d1af-47c5-9eaf-7ec10bc089e6" name="Default Changelist" comment="" />
34 + <created>1619424399162</created>
35 + <option name="number" value="Default" />
36 + <option name="presentableId" value="Default" />
37 + <updated>1619424399162</updated>
38 + <workItem from="1619424400378" duration="55000" />
39 + <workItem from="1620378646442" duration="2361000" />
40 + <workItem from="1621433178774" duration="882000" />
41 + <workItem from="1621502235218" duration="1898000" />
42 + <workItem from="1621509254458" duration="559000" />
43 + <workItem from="1622283631431" duration="5501000" />
44 + </task>
45 + <servers />
46 + </component>
47 + <component name="TypeScriptGeneratedFilesManager">
48 + <option name="version" value="3" />
49 + </component>
50 +</project>
...\ No newline at end of file ...\ No newline at end of file
...@@ -53,7 +53,7 @@ class DataProvider: ...@@ -53,7 +53,7 @@ class DataProvider:
53 querystring = querystring + '"' + target + '",' 53 querystring = querystring + '"' + target + '",'
54 querystring = querystring[:-1] 54 querystring = querystring[:-1]
55 querystring = querystring + 'from "StockPrice" ' + 'WHERE ' + '"id"=' + "'" + stockcode + stockdate + "'" 55 querystring = querystring + 'from "StockPrice" ' + 'WHERE ' + '"id"=' + "'" + stockcode + stockdate + "'"
56 - return self.DB.searchData(querystring, columns) 56 + return self.DB.searchData(querystring, columns)
57 57
58 def findSP(self, columns: List[str], stockcode: str, stock_startdate: str, stock_enddate: str): 58 def findSP(self, columns: List[str], stockcode: str, stock_startdate: str, stock_enddate: str):
59 if( self.DB ): 59 if( self.DB ):
......
1 from datetime import date 1 from datetime import date
2 import pandas as pd 2 import pandas as pd
3 -import sys 3 +import sys
4 from Investment.Strategy.StrategyBase import StrategyBase 4 from Investment.Strategy.StrategyBase import StrategyBase
5 5
6 -
7 class FinancialStatementsStrategyBase(StrategyBase): 6 class FinancialStatementsStrategyBase(StrategyBase):
8 AdditionalFinancialStatementsItem = [] 7 AdditionalFinancialStatementsItem = []
9 FinancialStatementsCondition = '' 8 FinancialStatementsCondition = ''
...@@ -17,13 +16,13 @@ class FinancialStatementsStrategyBase(StrategyBase): ...@@ -17,13 +16,13 @@ class FinancialStatementsStrategyBase(StrategyBase):
17 StockSearchTarget = [] 16 StockSearchTarget = []
18 FinancialStatementsOrderBy = [] 17 FinancialStatementsOrderBy = []
19 FinancialStatementsOrderMethod = '' 18 FinancialStatementsOrderMethod = ''
20 - 19 +
21 df_fs = None 20 df_fs = None
22 df_stock = None 21 df_stock = None
23 df_company = None 22 df_company = None
24 23
25 def __init__(self): 24 def __init__(self):
26 - super().__init__() 25 + super().__init__
27 self.Division = "FinancialStatements" 26 self.Division = "FinancialStatements"
28 27
29 def __repr__(self): 28 def __repr__(self):
...@@ -34,10 +33,8 @@ class FinancialStatementsStrategyBase(StrategyBase): ...@@ -34,10 +33,8 @@ class FinancialStatementsStrategyBase(StrategyBase):
34 33
35 def searchData(self): 34 def searchData(self):
36 try: 35 try:
37 - if self.df_fs is None: 36 + self.df_fs = self.db.findFS(self.FinancialStatementsSearchTarget, self.FinancialStatementsYear, self.FinancialStatementsQuater, self.FinancialStatementsDiv)
38 - self.df_fs = self.db.findFS(self.FinancialStatementsSearchTarget, self.FinancialStatementsYear, 37 + if( self.df_fs is None) :
39 - self.FinancialStatementsQuater, self.FinancialStatementsDiv)
40 - if self.df_fs is None:
41 print('db query error') 38 print('db query error')
42 sys.exit(1) 39 sys.exit(1)
43 except: 40 except:
...@@ -47,43 +44,54 @@ class FinancialStatementsStrategyBase(StrategyBase): ...@@ -47,43 +44,54 @@ class FinancialStatementsStrategyBase(StrategyBase):
47 44
48 def setAdditionalData(self): 45 def setAdditionalData(self):
49 try: 46 try:
50 - for item in self.AdditionalFinancialStatementsItem: 47 + for item in self.AdditionalFinancialStatementsItem:
51 self.df_fs[item] = 0 48 self.df_fs[item] = 0
52 - for item in self.StockSearchTarget: 49 +
50 + for item in self.StockSearchTarget:
53 self.df_fs[item] = 0 51 self.df_fs[item] = 0
54 52
55 for index, row in self.df_fs.iterrows(): 53 for index, row in self.df_fs.iterrows():
56 - self.df_stock = self.db.findSPbyID(self.StockSearchTarget, row['StockCode'], 54 + self.df_stock = self.db.findSPbyID(self.StockSearchTarget, row['StockCode'], self.StockDate.strftime("%Y-%m-%d"))
57 - self.StockDate.strftime("%Y-%m-%d")) 55 + if self.df_stock is None :
58 - if self.df_stock is None:
59 print('db query error') 56 print('db query error')
60 - else: 57 + else :
61 - if self.df_stock.size < 1: 58 + if self.df_stock.size < 1 :
62 continue 59 continue
63 - for item in self.StockSearchTarget: 60 + for item in self.StockSearchTarget:
64 self.df_fs.loc[index, item] = self.df_stock[item][0] 61 self.df_fs.loc[index, item] = self.df_stock[item][0]
65 - 62 +
66 for item in self.AdditionalFinancialStatementsItem: 63 for item in self.AdditionalFinancialStatementsItem:
67 if item == 'PER': 64 if item == 'PER':
68 - if row["ProfitLoss"] != 0: 65 + if row["ProfitLoss"] != 0 :
69 - self.df_fs.loc[index, item] = self.df_fs.loc[index, 'MarketCapitalization'] / row[ 66 + self.df_fs.loc[index, item] = self.df_fs.loc[index, 'MarketCapitalization']/row["ProfitLoss"]
70 - "ProfitLoss"]
71 elif item == 'PBR': 67 elif item == 'PBR':
72 - if row["Equity"] != 0: 68 + if row["Equity"] != 0 :
73 - self.df_fs.loc[index, item] = self.df_fs.loc[index, 'MarketCapitalization'] / row[ 69 + self.df_fs.loc[index, item] = self.df_fs.loc[index, 'MarketCapitalization']/row["Equity"]
74 - "Equity"]
75 elif item == 'ROE': 70 elif item == 'ROE':
76 - if row["Equity"] != 0: 71 + if row["Equity"] != 0 :
77 - self.df_fs.loc[index, item] = float(row["ProfitLoss"]) / float( 72 + self.df_fs.loc[index, item] = float(row["ProfitLoss"])/float(row["Equity"]) * 100.00
78 - row["Equity"]) * 100.00 73 + elif item == 'PSR':
74 + if row["Revenue"] != 0 :
75 + self.df_fs.loc[index, item] = self.df_fs.loc[index, 'MarketCapitalization']/row["Revenue"]
76 + elif item == 'PCR':
77 + if row["CashAndCashEquivalentsAtEndOfPeriodCf"] != 0 :
78 + self.df_fs.loc[index, item] = self.df_fs.loc[index, 'MarketCapitalization']/row["CashAndCashEquivalentsAtEndOfPeriodCf"]
79 + elif item == 'DR':
80 + if row["Equity"] != 0 :
81 + self.df_fs.loc[index, item] = float(row["Liabilities"])/float(row["Equity"]) * 100.00
82 + elif item == 'OM':
83 + if row["Revenue"] != 0 :
84 + self.df_fs.loc[index, item] = float(row["OperatingIncomeLoss"])/float(row["Revenue"]) * 100.00
85 + elif item == 'NPM':
86 + if row["Revenue"] != 0 :
87 + self.df_fs.loc[index, item] = float(row["ProfitLoss"])/float(row["Revenue"]) * 100.00
79 asc = True 88 asc = True
80 if self.FinancialStatementsOrderMethod == 'asc': 89 if self.FinancialStatementsOrderMethod == 'asc':
81 asc = True 90 asc = True
82 elif self.FinancialStatementsOrderMethod == 'desc': 91 elif self.FinancialStatementsOrderMethod == 'desc':
83 asc = False 92 asc = False
84 - self.df_all = self.df_fs.query(self.FinancialStatementsCondition).sort_values( 93 + self.df_all = self.df_fs.query(self.FinancialStatementsCondition).sort_values(by=self.FinancialStatementsOrderBy, ascending=asc).head(self.NumberOfStocks)
85 - by=self.FinancialStatementsOrderBy, ascending=asc).head(self.NumberOfStocks) 94 + self.df_all.insert(1,'StockName','')
86 - self.df_all.insert(1, 'StockName', '')
87 self.df_all['StockName'] = '' 95 self.df_all['StockName'] = ''
88 96
89 for index, row in self.df_all.iterrows(): 97 for index, row in self.df_all.iterrows():
...@@ -93,3 +101,4 @@ class FinancialStatementsStrategyBase(StrategyBase): ...@@ -93,3 +101,4 @@ class FinancialStatementsStrategyBase(StrategyBase):
93 print("Unexpected error:", sys.exc_info()[0]) 101 print("Unexpected error:", sys.exc_info()[0])
94 return False 102 return False
95 return True 103 return True
104 +
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -34,7 +34,7 @@ class TradingBase: ...@@ -34,7 +34,7 @@ class TradingBase:
34 if self.BuyingMethod == 1: 34 if self.BuyingMethod == 1:
35 investmentAmount = self.TotalInvestmentAmount / self.NumberOfStocks 35 investmentAmount = self.TotalInvestmentAmount / self.NumberOfStocks
36 for index, row in self.df_all.iterrows(): 36 for index, row in self.df_all.iterrows():
37 - self.df_stock = self.db.findSPbyID(self.StockBuyingSearchTarget, self.df_all.loc[index, 'StockCode'], self.BuyingDateTime[0].strftime("%Y-%m-%d")) 37 + self.df_stock = self.db.findSPbyID(self.StockBuyingSearchTarget, self.df_all.loc[index, 'StockCode'], self.BuyingDateTime[0].strftime("%Y-%m-%d"))
38 if self.df_stock is None : 38 if self.df_stock is None :
39 print('db query error') 39 print('db query error')
40 else: 40 else:
...@@ -42,7 +42,7 @@ class TradingBase: ...@@ -42,7 +42,7 @@ class TradingBase:
42 continue 42 continue
43 buyingPrice = self.df_stock[self.StockBuyingSearchTarget[0]][0] 43 buyingPrice = self.df_stock[self.StockBuyingSearchTarget[0]][0]
44 44
45 - self.df_stock = self.db.findSPbyID(self.StockSellSearchTarget, self.df_all.loc[index, 'StockCode'], self.SellDateTime[0].strftime("%Y-%m-%d")) 45 + self.df_stock = self.db.findSPbyID(self.StockSellSearchTarget, self.df_all.loc[index, 'StockCode'], self.SellDateTime[0].strftime("%Y-%m-%d"))
46 if self.df_stock is None : 46 if self.df_stock is None :
47 print('db query error') 47 print('db query error')
48 else: 48 else:
...@@ -54,7 +54,6 @@ class TradingBase: ...@@ -54,7 +54,6 @@ class TradingBase:
54 self.df_all.loc[index, 'SellPrice'] = sellPrice 54 self.df_all.loc[index, 'SellPrice'] = sellPrice
55 self.df_all.loc[index, 'BuyingAmount'] = int(investmentAmount / buyingPrice) 55 self.df_all.loc[index, 'BuyingAmount'] = int(investmentAmount / buyingPrice)
56 56
57 -
58 elif self.BuyingMethod == 2: 57 elif self.BuyingMethod == 2:
59 print('...') 58 print('...')
60 else: 59 else:
......
1 import pandas as pd 1 import pandas as pd
2 import json 2 import json
3 3
4 -
5 class VerificationBase: 4 class VerificationBase:
6 Name = '' 5 Name = ''
7 TotalInvestmentAmount = 0 6 TotalInvestmentAmount = 0
8 Balance: int = 0 7 Balance: int = 0
9 Yield: float = 0 8 Yield: float = 0
10 - 9 +
11 - df_all = None # type: pd 10 + df_all = None # type: pd
12 db = None 11 db = None
13 12
14 def __init__(self): 13 def __init__(self):
...@@ -21,10 +20,10 @@ class VerificationBase: ...@@ -21,10 +20,10 @@ class VerificationBase:
21 print("setVerification") 20 print("setVerification")
22 21
23 def doVerification(self): 22 def doVerification(self):
24 - self.df_all['ProfitLossByStock'] = 0 23 + self.df_all['ProfitLossByStock'] = 0
25 - self.df_all['InvestmentAmount'] = 0 24 + self.df_all['InvestmentAmount'] = 0
26 - self.df_all['Balance'] = 0 25 + self.df_all['Balance'] = 0
27 - self.df_all['Yield'] = 0 26 + self.df_all['Yield'] = 0
28 27
29 for index, row in self.df_all.iterrows(): 28 for index, row in self.df_all.iterrows():
30 buyingPrice = self.df_all.loc[index, 'BuyingPrice'] 29 buyingPrice = self.df_all.loc[index, 'BuyingPrice']
...@@ -32,22 +31,19 @@ class VerificationBase: ...@@ -32,22 +31,19 @@ class VerificationBase:
32 investmentCurrentAmount = self.df_all.loc[index, 'BuyingAmount'] * buyingPrice 31 investmentCurrentAmount = self.df_all.loc[index, 'BuyingAmount'] * buyingPrice
33 self.df_all.loc[index, 'ProfitLossByStock'] = sellPrice - buyingPrice 32 self.df_all.loc[index, 'ProfitLossByStock'] = sellPrice - buyingPrice
34 self.df_all.loc[index, 'InvestmentAmount'] = investmentCurrentAmount 33 self.df_all.loc[index, 'InvestmentAmount'] = investmentCurrentAmount
35 - self.df_all.loc[index, 'Balance'] = investmentCurrentAmount + self.df_all.loc[index, 'ProfitLossByStock'] * \ 34 + self.df_all.loc[index, 'Balance'] = investmentCurrentAmount + self.df_all.loc[index, 'ProfitLossByStock'] * self.df_all.loc[index, 'BuyingAmount']
36 - self.df_all.loc[index, 'BuyingAmount'] 35 + self.df_all.loc[index, 'Yield'] = (float(self.df_all.loc[index, 'Balance']) - float(investmentCurrentAmount))/float(investmentCurrentAmount) * 100.00
37 - self.df_all.loc[index, 'Yield'] = (float(self.df_all.loc[index, 'Balance']) - float( 36 +
38 - investmentCurrentAmount)) / float(investmentCurrentAmount) * 100.00
39 -
40 self.Balance = self.df_all['Balance'].sum() 37 self.Balance = self.df_all['Balance'].sum()
41 investmentCurrentTotalAmount = self.df_all['InvestmentAmount'].sum() 38 investmentCurrentTotalAmount = self.df_all['InvestmentAmount'].sum()
42 - self.df_all = self.df_all.append(pd.Series(), ignore_index=True) 39 + self.df_all = self.df_all.append(pd.Series(), ignore_index = True)
43 - self.df_all.loc[len(self.df_all) - 1, 'Balance'] = self.Balance 40 + self.df_all.loc[len(self.df_all)-1, 'Balance'] = self.Balance
44 - self.Yield = ((float(self.Balance) + float(self.TotalInvestmentAmount - investmentCurrentTotalAmount)) - float( 41 + self.Yield = ((float(self.Balance) + float(self.TotalInvestmentAmount - investmentCurrentTotalAmount)) - float(self.TotalInvestmentAmount))/float(self.TotalInvestmentAmount) * 100.00
45 - self.TotalInvestmentAmount)) / float(self.TotalInvestmentAmount) * 100.00 42 + self.df_all.loc[len(self.df_all)-1, 'Yield'] = self.Yield
46 - self.df_all.loc[len(self.df_all) - 1, 'Yield'] = self.Yield
47 43
48 def saveResult(self): 44 def saveResult(self):
49 - self.df_all.to_csv("result1.csv") 45 + self.df_all.to_csv("result.csv")
50 - self.df_all.to_csv("result_kr1.csv", encoding='euc-kr') 46 + self.df_all.to_csv("result_kr.csv", encoding='euc-kr')
51 47
52 def saveResulToJSON(self): 48 def saveResulToJSON(self):
53 result = self.df_all.to_json(orient="split") 49 result = self.df_all.to_json(orient="split")
...@@ -55,23 +51,9 @@ class VerificationBase: ...@@ -55,23 +51,9 @@ class VerificationBase:
55 with open("result.json", "w") as text_file: 51 with open("result.json", "w") as text_file:
56 text_file.write(json.dumps(parsed, indent=4, ensure_ascii=False)) 52 text_file.write(json.dumps(parsed, indent=4, ensure_ascii=False))
57 53
58 - def saveSummary(self, record, num): 54 + def saveSummary(self):
59 - self.Yield = round(self.Yield, 5) 55 + jsonobj = { "TotalInvestmentAmount" : str(self.TotalInvestmentAmount), "Balance" : str(self.Balance), "Yield": str(self.Yield)}
60 - if record[-1] < self.Yield: 56 + with open("result_summary.json", "w") as text_file:
61 - if record[0] == 0: 57 + text_file.write(json.dumps(jsonobj, indent=4))
62 - record[0] = self.Yield 58 +
63 - else: 59 +
64 - for i in range(5):
65 - if record[i] == self.Yield:
66 - return False, 0
67 - elif record[i] < self.Yield:
68 - record.insert(i, self.Yield)
69 - break
70 - if len(record) > 5:
71 - record.pop()
72 - jsonobj = {"TotalInvestmentAmount": str(self.TotalInvestmentAmount), "Balance": str(self.Balance),
73 - "Yield": str(self.Yield)}
74 - with open(f"result_summary{num}.json", "w") as text_file:
75 - text_file.write(json.dumps(jsonobj, indent=4))
76 - return True, self.Yield
77 - return False, 0
......
1 +from Investment.Strategy.FinancialStatementsStrategyBase import FinancialStatementsStrategyBase
2 +from datetime import date
3 +
4 +
5 +class Strategy(FinancialStatementsStrategyBase):
6 + def __init__(self):
7 + super().__init__
8 +
9 + def __repr__(self):
10 + return self.Name
11 +
12 + def setStrategy(self):
13 + super().setStrategy()
14 + self.Name = 'PER_ROE_V1.0'
15 + self.NumberOfStocks = 10
16 + self.AdditionalFinancialStatementsItem.append('PER')
17 + self.AdditionalFinancialStatementsItem.append('PBR')
18 + self.AdditionalFinancialStatementsItem.append('ROE')
19 + self.FinancialStatementsCondition = '(PER > 0) and (PBR < 0.7) and (ROE > 11)'
20 + self.FinancialStatementsYear = 2016
21 + self.FinancialStatementsQuater = 4
22 + self.FinancialStatementsDiv = 'CFS'
23 + self.StockDate = date(2017, 4, 10)
24 + self.FinancialStatementsSearchTarget.append('StockCode')
25 + self.FinancialStatementsSearchTarget.append('Equity')
26 + self.FinancialStatementsSearchTarget.append('ProfitLoss')
27 + self.FinancialStatementsSearchTarget.append('CashAndCashEquivalentsAtEndOfPeriodCf')
28 + self.FinancialStatementsSearchTarget.append('Revenue')
29 + self.StockSearchTarget.append('MarketCapitalization')
30 + self.FinancialStatementsOrderBy.append('PER')
31 + self.FinancialStatementsOrderMethod = 'asc'
32 +
33 + def searchData(self):
34 + return FinancialStatementsStrategyBase.searchData(self)
35 +
36 + def setAdditionalData(self):
37 + return FinancialStatementsStrategyBase.setAdditionalData(self)
1 from Investment.Trading.TradingBase import TradingBase 1 from Investment.Trading.TradingBase import TradingBase
2 from datetime import date 2 from datetime import date
3 3
4 +
4 class Trading(TradingBase): 5 class Trading(TradingBase):
5 def __init__(self): 6 def __init__(self):
6 super().__init__ 7 super().__init__
7 - 8 +
8 def __repr__(self): 9 def __repr__(self):
9 return self.Name 10 return self.Name
10 11
...@@ -12,14 +13,14 @@ class Trading(TradingBase): ...@@ -12,14 +13,14 @@ class Trading(TradingBase):
12 super().setTrading() 13 super().setTrading()
13 self.Name = 'Split evenly' 14 self.Name = 'Split evenly'
14 self.TotalInvestmentAmount = 100000000 15 self.TotalInvestmentAmount = 100000000
15 - self.Method = 1 # 1 : "Split evenly", 16 + self.Method = 1 # 1 : "Split evenly",
16 self.BuyingMethod = 1 # 1 : at once 17 self.BuyingMethod = 1 # 1 : at once
17 - self.BuyingDateTime = [date(2017, 4, 10)] 18 + self.BuyingDateTime.append(date(2017, 4, 10))
18 - self.SellDateTime = [date(2018, 4, 16)] 19 + self.SellDateTime.append(date(2017, 7, 10))
19 self.NumberOfStocks = 10 20 self.NumberOfStocks = 10
20 self.PriceDiv = 'Open' 21 self.PriceDiv = 'Open'
21 - self.StockBuyingSearchTarget = ['Open'] 22 + self.StockBuyingSearchTarget.append('Open')
22 - self.StockSellSearchTarget = ['Open'] 23 + self.StockSellSearchTarget.append('Open')
23 24
24 def doTrading(self): 25 def doTrading(self):
25 - return super().doTrading()
...\ No newline at end of file ...\ No newline at end of file
26 + return super().doTrading()
......
1 from Investment.Verification.VerificationBase import VerificationBase 1 from Investment.Verification.VerificationBase import VerificationBase
2 from datetime import date 2 from datetime import date
3 3
4 -
5 class Verification(VerificationBase): 4 class Verification(VerificationBase):
6 def __init__(self): 5 def __init__(self):
7 super().__init__ 6 super().__init__
8 - 7 +
9 def __repr__(self): 8 def __repr__(self):
10 return self.Name 9 return self.Name
11 10
...@@ -13,13 +12,15 @@ class Verification(VerificationBase): ...@@ -13,13 +12,15 @@ class Verification(VerificationBase):
13 super().setVerification() 12 super().setVerification()
14 13
15 def doVerification(self): 14 def doVerification(self):
16 - return super().doVerification() 15 + return super().doVerification()
17 16
18 def saveResult(self): 17 def saveResult(self):
19 - return super().saveResult() 18 + return super().saveResult()
20 19
21 def saveResulToJSON(self): 20 def saveResulToJSON(self):
22 - return super().saveResulToJSON() 21 + return super().saveResulToJSON()
22 +
23 + def saveSummary(self):
24 + return super().saveSummary()
23 25
24 - def saveSummary(self, record, num): 26 +
25 - return super().saveSummary(record, num)
...\ No newline at end of file ...\ No newline at end of file
......
1 +import Strategy
2 +import Trading
3 +import Verification
4 +import sys
5 +import DataProvider
6 +
7 +st = Strategy.Strategy()
8 +tr = Trading.Trading()
9 +ve = Verification.Verification()
10 +db = DataProvider.DataProvider()
11 +
12 +if db.initialize():
13 + print('db connection')
14 +
15 + st.db = db
16 + st.setStrategy()
17 + if st.searchData() == False:
18 + print("st.searchData error")
19 + sys.exit(-1)
20 + if st.setAdditionalData() == False:
21 + print("st.setAdditionalData error")
22 + sys.exit(-1)
23 +
24 + tr.df_all = st.df_all
25 + tr.db = db
26 + tr.setTrading()
27 + if tr.doTrading() == False:
28 + print("tr.doTrading error")
29 + sys.exit(-1)
30 +
31 + ve.TotalInvestmentAmount = tr.TotalInvestmentAmount
32 + ve.df_all = tr.df_all
33 + ve.setVerification()
34 + ve.doVerification()
35 + ve.saveResult()
36 + # ve.saveResulToJSON()
37 + ve.saveSummary()
38 +else:
39 + print("db error")
40 +db.close()
1 +,StockCode,StockName,Equity,ProfitLoss,CashAndCashEquivalentsAtEndOfPeriodCf,Revenue,PER,MarketCapitalization,PBR,ROE,BuyingPrice,SellPrice,BuyingAmount,ProfitLossByStock,InvestmentAmount,Balance,Yield
2 +0,084110,휴온스글로벌,453898247468.0,526207281324.0,91075668352.0,163712232478.0,0.48942596794175863,257539508000.0,0.5673948058549326,115.93067042214078,28050.0,37550.0,356.0,9500.0,9985800.0,13367800.0,33.8680926916221
3 +1,032940,원익,123949666954.0,82550453825.0,1388965901.0,64804004293.0,0.8570857690254496,70752819200.0,0.5708189536826885,66.59998034172693,5570.0,7180.0,1795.0,1610.0,9998150.0,12888100.0,28.904847396768403
4 +2,007860,서연,1072030023657.0,132366474007.0,291668735819.0,3188334589765.0,1.7827205413624674,235972432200.0,0.22011737264132844,12.347273032098506,10150.0,10250.0,985.0,100.0,9997750.0,10096250.0,0.9852216748768473
5 +3,030530,원익홀딩스,722074414944.0,198963997320.0,31875697734.0,294905605408.0,2.352496789191469,468062164860.0,0.6482187364252482,27.55450036758753,6090.0,8040.0,1642.0,1950.0,9999780.0,13201680.0,32.01970443349754
6 +4,023600,삼보판지,329937058742.0,40288485800.0,13938600553.0,326686709919.0,2.380332695452158,95900000000.0,0.29066149878904834,12.210961070458072,6860.0,6750.0,1457.0,-110.0,9995020.0,9834750.0,-1.6034985422740524
7 +5,033160,엠케이전자,593852198159.0,74507668124.0,46704481994.0,619601002744.0,2.391281644105155,178168819130.0,0.30002215986122605,12.546500350589099,8360.0,10000.0,1196.0,1640.0,9998560.0,11960000.0,19.617224880382775
8 +6,081660,휠라홀딩스,1302162825904.0,311126247136.0,149389365351.0,967128444713.0,2.8011166085227392,871500898200.0,0.6692718305753954,23.893037103098607,70400.0,78900.0,142.0,8500.0,9996800.0,11203800.0,12.073863636363637
9 +7,037460,삼지전자,212713055001.0,38468337750.0,2657308940.0,1101581286777.0,2.9180729786017334,112253416920.0,0.5277222731791064,18.084615328297154,8130.0,8510.0,1230.0,380.0,9999900.0,10467300.0,4.674046740467404
10 +8,005710,대원산업,221444272333.0,42811295063.0,108076996577.0,823571832855.0,2.9784663092381725,127512000000.0,0.575819815326955,19.332762420073752,7150.0,7110.0,1398.0,-40.0,9995700.0,9939780.0,-0.5594405594405595
11 +9,122450,KMH,276591210392.0,35617262232.0,53301802111.0,159467610459.0,2.9847171536527886,106307453550.0,0.38434863276868175,12.877221290409516,7950.0,9400.0,1257.0,1450.0,9993150.0,11815800.0,18.238993710691823
12 +10,,,,,,,,,,,,,,,,114775260.0,14.814649999999999
1 +,StockCode,StockName,Equity,ProfitLoss,CashAndCashEquivalentsAtEndOfPeriodCf,Revenue,PER,MarketCapitalization,PBR,ROE,BuyingPrice,SellPrice,BuyingAmount,ProfitLossByStock,InvestmentAmount,Balance,Yield
2 +0,084110,휴온스글로벌,453898247468.0,526207281324.0,91075668352.0,163712232478.0,0.48942596794175863,257539508000.0,0.5673948058549326,115.93067042214078,28050.0,37550.0,356.0,9500.0,9985800.0,13367800.0,33.8680926916221
3 +1,032940,원익,123949666954.0,82550453825.0,1388965901.0,64804004293.0,0.8570857690254496,70752819200.0,0.5708189536826885,66.59998034172693,5570.0,7180.0,1795.0,1610.0,9998150.0,12888100.0,28.904847396768403
4 +2,007860,서연,1072030023657.0,132366474007.0,291668735819.0,3188334589765.0,1.7827205413624674,235972432200.0,0.22011737264132844,12.347273032098506,10150.0,10250.0,985.0,100.0,9997750.0,10096250.0,0.9852216748768473
5 +3,030530,원익홀딩스,722074414944.0,198963997320.0,31875697734.0,294905605408.0,2.352496789191469,468062164860.0,0.6482187364252482,27.55450036758753,6090.0,8040.0,1642.0,1950.0,9999780.0,13201680.0,32.01970443349754
6 +4,023600,삼보판지,329937058742.0,40288485800.0,13938600553.0,326686709919.0,2.380332695452158,95900000000.0,0.29066149878904834,12.210961070458072,6860.0,6750.0,1457.0,-110.0,9995020.0,9834750.0,-1.6034985422740524
7 +5,033160,엠케이전자,593852198159.0,74507668124.0,46704481994.0,619601002744.0,2.391281644105155,178168819130.0,0.30002215986122605,12.546500350589099,8360.0,10000.0,1196.0,1640.0,9998560.0,11960000.0,19.617224880382775
8 +6,081660,휠라홀딩스,1302162825904.0,311126247136.0,149389365351.0,967128444713.0,2.8011166085227392,871500898200.0,0.6692718305753954,23.893037103098607,70400.0,78900.0,142.0,8500.0,9996800.0,11203800.0,12.073863636363637
9 +7,037460,삼지전자,212713055001.0,38468337750.0,2657308940.0,1101581286777.0,2.9180729786017334,112253416920.0,0.5277222731791064,18.084615328297154,8130.0,8510.0,1230.0,380.0,9999900.0,10467300.0,4.674046740467404
10 +8,005710,대원산업,221444272333.0,42811295063.0,108076996577.0,823571832855.0,2.9784663092381725,127512000000.0,0.575819815326955,19.332762420073752,7150.0,7110.0,1398.0,-40.0,9995700.0,9939780.0,-0.5594405594405595
11 +9,122450,KMH,276591210392.0,35617262232.0,53301802111.0,159467610459.0,2.9847171536527886,106307453550.0,0.38434863276868175,12.877221290409516,7950.0,9400.0,1257.0,1450.0,9993150.0,11815800.0,18.238993710691823
12 +10,,,,,,,,,,,,,,,,114775260.0,14.814649999999999
1 { 1 {
2 "TotalInvestmentAmount": "100000000", 2 "TotalInvestmentAmount": "100000000",
3 - "Balance": "103082220", 3 + "Balance": "114775260",
4 - "Yield": "3.100435" 4 + "Yield": "14.814649999999999"
5 } 5 }
...\ No newline at end of file ...\ No newline at end of file
......