From 152de00783ffd91bf771acf38eab5a6928006350 Mon Sep 17 00:00:00 2001 From: Ayuriel Date: Sat, 29 Mar 2025 19:17:49 +0900 Subject: [PATCH] =?UTF-8?q?chore:=20=ED=8C=A8=ED=82=A4=EC=A7=80=20?= =?UTF-8?q?=EA=B5=AC=EC=A1=B0=20=EB=B3=80=EA=B2=BD(=EC=8B=A4=ED=96=89=20?= =?UTF-8?q?=EC=95=88=20=EB=90=A8)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- example/10-calculate-stock-value.py | 2 +- example/10-financial-statements-one.py | 4 +- example/10-financial-statements.py | 2 +- example/10-stock-data.py | 2 +- example/10-stock-price.py | 2 +- example/13-kor-momentum-portfolio.py | 2 +- example/13-kor-value-portfolio.py | 2 +- example/13-magic-formula-portfolio.py | 2 +- example/13-multi-factor-portfolio.py | 2 +- example/13-quality-portfolio.py | 2 +- streamlit_quant/__init__.py | 2 +- streamlit_quant/app.py | 6 +- streamlit_quant/backtest/backtest-1.py | 2 +- streamlit_quant/{pages => }/crawling.py | 0 streamlit_quant/pages/super_quality.py | 41 ------------ .../quantcommon.py | 0 .../src/current-financial-statements.py | 3 +- streamlit_quant/src/current-price.py | 4 +- streamlit_quant/src/current-stock.py | 2 +- streamlit_quant/strategy/__init__.py | 2 +- streamlit_quant/strategy/all_value.py | 3 +- streamlit_quant/strategy/f_score.py | 3 +- streamlit_quant/strategy/magic_formula.py | 6 +- streamlit_quant/strategy/momentum.py | 2 +- streamlit_quant/strategy/quality.py | 3 +- streamlit_quant/strategy/value.py | 3 +- streamlit_quant/super_quality.py | 67 +++++++++++++++++++ .../{pages => }/super_value_momentum.py | 0 29 files changed, 100 insertions(+), 73 deletions(-) rename streamlit_quant/{pages => }/crawling.py (100%) delete mode 100644 streamlit_quant/pages/super_quality.py rename quantcommon.py => streamlit_quant/quantcommon.py (100%) create mode 100644 streamlit_quant/super_quality.py rename streamlit_quant/{pages => }/super_value_momentum.py (100%) diff --git a/README.md b/README.md index 45ea151..6034df6 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # 실행 -streamlit run .\streamlit-quant\app.py --server.port 20000 +streamlit run app.py --server.port=20000 # pre- Go to Build Tools for Visual Studio 2017 diff --git a/example/10-calculate-stock-value.py b/example/10-calculate-stock-value.py index d21d9d8..faed060 100644 --- a/example/10-calculate-stock-value.py +++ b/example/10-calculate-stock-value.py @@ -2,7 +2,7 @@ import numpy as np import pandas as pd -import quantcommon +from streamlit_quant import quantcommon # DB 연결 common = quantcommon.QuantCommon() diff --git a/example/10-financial-statements-one.py b/example/10-financial-statements-one.py index ded0d36..dedad5f 100644 --- a/example/10-financial-statements-one.py +++ b/example/10-financial-statements-one.py @@ -1,12 +1,10 @@ import re -import time import pandas as pd import requests as rq from bs4 import BeautifulSoup -from tqdm import tqdm -import quantcommon +from streamlit_quant import quantcommon # DB 연결 common = quantcommon.QuantCommon() diff --git a/example/10-financial-statements.py b/example/10-financial-statements.py index 170aedb..807b406 100644 --- a/example/10-financial-statements.py +++ b/example/10-financial-statements.py @@ -6,7 +6,7 @@ import requests as rq from bs4 import BeautifulSoup from tqdm import tqdm -import quantcommon +from streamlit_quant import quantcommon # src/current-financial-statement.py 로 개선 # DB 연결 diff --git a/example/10-stock-data.py b/example/10-stock-data.py index 398897c..c19c525 100644 --- a/example/10-stock-data.py +++ b/example/10-stock-data.py @@ -8,7 +8,7 @@ import requests as rq from tqdm import tqdm from bs4 import BeautifulSoup from dotenv import load_dotenv -import quantcommon +from streamlit_quant import quantcommon # src/current-stock.py 로 개선 load_dotenv() diff --git a/example/10-stock-price.py b/example/10-stock-price.py index 050cb74..46a3385 100644 --- a/example/10-stock-price.py +++ b/example/10-stock-price.py @@ -9,7 +9,7 @@ import requests as rq from dateutil.relativedelta import relativedelta from tqdm import tqdm -import quantcommon +from streamlit_quant import quantcommon # src/current-price.py 로 개선 diff --git a/example/13-kor-momentum-portfolio.py b/example/13-kor-momentum-portfolio.py index 22cc264..32571f5 100644 --- a/example/13-kor-momentum-portfolio.py +++ b/example/13-kor-momentum-portfolio.py @@ -3,7 +3,7 @@ import matplotlib.pyplot as plt import seaborn as sns import statsmodels.api as sm import numpy as np -import quantcommon +from streamlit_quant import quantcommon # strategy/momentum에 구현 # 모멘텀 포트폴리오. 최근 12개월 수익률이 높은 주식 diff --git a/example/13-kor-value-portfolio.py b/example/13-kor-value-portfolio.py index 59c4a7c..873a539 100644 --- a/example/13-kor-value-portfolio.py +++ b/example/13-kor-value-portfolio.py @@ -1,6 +1,6 @@ import pandas as pd import numpy as np -import quantcommon +from streamlit_quant import quantcommon # strategy/value 에서 구현 diff --git a/example/13-magic-formula-portfolio.py b/example/13-magic-formula-portfolio.py index eac3537..2ca637d 100644 --- a/example/13-magic-formula-portfolio.py +++ b/example/13-magic-formula-portfolio.py @@ -2,7 +2,7 @@ import pandas as pd import numpy as np import matplotlib.pyplot as plt import seaborn as sns -import quantcommon +from streamlit_quant import quantcommon # 마법 공식 포트폴리오. 밸류와 퀄리티의 조합. 조엘 그린블라트의 '마법공식 engine = quantcommon.QuantCommon().create_engine() diff --git a/example/13-multi-factor-portfolio.py b/example/13-multi-factor-portfolio.py index d04f3ed..0658f75 100644 --- a/example/13-multi-factor-portfolio.py +++ b/example/13-multi-factor-portfolio.py @@ -4,7 +4,7 @@ import statsmodels.api as sm from scipy.stats import zscore import matplotlib.pyplot as plt import seaborn as sns -import quantcommon +from streamlit_quant import quantcommon # strategy/multi-factor에서 구현 diff --git a/example/13-quality-portfolio.py b/example/13-quality-portfolio.py index 7380c64..82fb2c6 100644 --- a/example/13-quality-portfolio.py +++ b/example/13-quality-portfolio.py @@ -2,7 +2,7 @@ import pandas as pd import numpy as np import matplotlib.pyplot as plt import seaborn as sns -import quantcommon +from streamlit_quant import quantcommon # strategy/quality에서 구현 diff --git a/streamlit_quant/__init__.py b/streamlit_quant/__init__.py index 04bd080..e6c67f5 100644 --- a/streamlit_quant/__init__.py +++ b/streamlit_quant/__init__.py @@ -1 +1 @@ -__all__ = ['backtest', 'strategy'] \ No newline at end of file +__all__ = ['backtest', 'strategy', 'quantcommon'] \ No newline at end of file diff --git a/streamlit_quant/app.py b/streamlit_quant/app.py index 616436e..24380ea 100644 --- a/streamlit_quant/app.py +++ b/streamlit_quant/app.py @@ -1,8 +1,8 @@ import streamlit as st -crawling_page = st.Page("pages/crawling.py", title="크롤링") -super_quality_page = st.Page("pages/super_quality.py", title="슈퍼 퀄리티 전략") -super_value_momentum_page = st.Page("pages/super_value_momentum.py", title="슈퍼 밸류 모멘텀 전략") +crawling_page = st.Page("crawling.py", title="크롤링") +super_quality_page = st.Page("super_quality.py", title="슈퍼 퀄리티 전략") +super_value_momentum_page = st.Page("super_value_momentum.py", title="슈퍼 밸류 모멘텀 전략") pg = st.navigation({ '크롤링': [crawling_page], diff --git a/streamlit_quant/backtest/backtest-1.py b/streamlit_quant/backtest/backtest-1.py index 791d7b5..1f2731e 100644 --- a/streamlit_quant/backtest/backtest-1.py +++ b/streamlit_quant/backtest/backtest-1.py @@ -3,7 +3,7 @@ import matplotlib.pyplot as plt import pandas as pd -import quantcommon +from streamlit_quant import quantcommon import streamlit_quant.strategy.multi_factor as multi_factor import streamlit_quant.strategy.magic_formula as magic_formula diff --git a/streamlit_quant/pages/crawling.py b/streamlit_quant/crawling.py similarity index 100% rename from streamlit_quant/pages/crawling.py rename to streamlit_quant/crawling.py diff --git a/streamlit_quant/pages/super_quality.py b/streamlit_quant/pages/super_quality.py deleted file mode 100644 index 5ee1f0f..0000000 --- a/streamlit_quant/pages/super_quality.py +++ /dev/null @@ -1,41 +0,0 @@ -import streamlit as st - -st.write(""" -'신F-스코어 3점 + 고GP/A 전략'을 '강환국 슈퍼 퀄리티 전략'이라 명명한다. -이 전략은 신F-스코어가 3점인 종목을 매수하되, GP/A로 순위를 매겨서 순위가 높은 종목만 매수하는 것이다. -이 경우 한국에서 수익이 어땠을지 분석해보자. -연도별로 신F-스코어 3점을 충족하는 종목은 600-700개였다.\n -신F-스코어 3점 기업 내에서도 GP/A가 높은 종목이 3점 종목 평균보다 CAGR 기준으로 3-4% 더 높았다. -반대로 GP/A가 낮은 종목의 수익률은 상대적으로 저조했다.\n\n ---- -투자 전략: 강환국 슈퍼 퀄리티 전략 1.0\n -레벨: 초, 중급\n -스타일: 퀄리티\n -기대 CAGR: 약 20%\n -매수 전략: -- 신F-스코어 3점 종목만 매수\n -- 여기에 GP/A 순위를 부여, 순위 높은 20-30종목을 매수\n -매도 전략: 연 1회 리밸런싱\n\n\n ---- -지금까지 소개한 거의 모든 전략에서 소형주 전략이 전체 주식 수익률보다 높았다. -시가총액 하위 20% 종목의 CAGR을 분석해보았다.\n\n ---- -투자 전략: 강환국 슈퍼 퀄리티 전략 2.0\n -레벨: 초, 중급\n -스타일: 퀄리티\n -기대 CAGR: 20% 이상\n -매수 전략: -아래 조건을 만족하는 20-30종목 매수\n -- 신F-스코어 3점 종목만 매수\n -- 여기에 GP/A 순위를 부여, 순위 높은 종목만 매수\n -- 단, 소형주(시가총액 최저 20%)만 매수\n -매도 전략: 연 1회 리밸런싱\n ---- -소형주 중 신F-스코어가 3점인 종목을 찾아보니 2004-2016년 구간에 80-100개 종목이 남았다. -그 주식들을 통째로 매수해도 CAGR 34.55%를 벌수 있었다! -정말 상당한 수익이다. -이 종목들을 다 샀으면 총 1,159개 종목 중 14개가 파산했다.(1.2%) -또 1년간 마이너스 수익을 기록한 종목이 29.7%였다.\n -신F-스코어가 3점인 종목 중 GP/A가 높은 종목 위주로 매수했으면 (1) CAGR도 조금 개선되고 (2) 최상 30개 종목을 매수했을 경우 선택받은 종목 360개 중 파산한 기업은 단 1개였다. -F-스코어와 GP/A는 엄청난 잠재력을 지닌 콤비네이션임이 분명하다. -""") \ No newline at end of file diff --git a/quantcommon.py b/streamlit_quant/quantcommon.py similarity index 100% rename from quantcommon.py rename to streamlit_quant/quantcommon.py diff --git a/streamlit_quant/src/current-financial-statements.py b/streamlit_quant/src/current-financial-statements.py index 004eb8a..ddaf748 100644 --- a/streamlit_quant/src/current-financial-statements.py +++ b/streamlit_quant/src/current-financial-statements.py @@ -6,7 +6,8 @@ import requests as rq from bs4 import BeautifulSoup from tqdm import tqdm -import quantcommon +from streamlit_quant import quantcommon + # 재무제표 크롤링 diff --git a/streamlit_quant/src/current-price.py b/streamlit_quant/src/current-price.py index 9b3ed8e..34cb3e2 100644 --- a/streamlit_quant/src/current-price.py +++ b/streamlit_quant/src/current-price.py @@ -6,10 +6,10 @@ from io import BytesIO import pandas as pd import requests as rq -from dateutil.relativedelta import relativedelta from tqdm import tqdm -import quantcommon +from streamlit_quant import quantcommon + # 주가 크롤링 diff --git a/streamlit_quant/src/current-stock.py b/streamlit_quant/src/current-stock.py index 0b06390..46c1d2d 100644 --- a/streamlit_quant/src/current-stock.py +++ b/streamlit_quant/src/current-stock.py @@ -8,7 +8,7 @@ import requests as rq from tqdm import tqdm from bs4 import BeautifulSoup from dotenv import load_dotenv -import quantcommon +from streamlit_quant import quantcommon load_dotenv() diff --git a/streamlit_quant/strategy/__init__.py b/streamlit_quant/strategy/__init__.py index cb7180d..8a05387 100644 --- a/streamlit_quant/strategy/__init__.py +++ b/streamlit_quant/strategy/__init__.py @@ -1 +1 @@ -__all__ = ['multi_factor'] \ No newline at end of file +__all__ = ['multi_factor', 'f_score'] \ No newline at end of file diff --git a/streamlit_quant/strategy/all_value.py b/streamlit_quant/strategy/all_value.py index 38b945a..4b35a8b 100644 --- a/streamlit_quant/strategy/all_value.py +++ b/streamlit_quant/strategy/all_value.py @@ -1,7 +1,8 @@ import matplotlib.pyplot as plt import numpy as np import seaborn as sns -import quantcommon +from streamlit_quant import quantcommon + #가치주 포트폴리오. PER, PBR, PCR, PSR, DY def get_all_value_top(count): diff --git a/streamlit_quant/strategy/f_score.py b/streamlit_quant/strategy/f_score.py index 7970925..e54d0d7 100644 --- a/streamlit_quant/strategy/f_score.py +++ b/streamlit_quant/strategy/f_score.py @@ -1,6 +1,7 @@ from datetime import datetime import pandas as pd -import quantcommon +from streamlit_quant import quantcommon + # 흑자 기업이면 1점(당기순이익) def calc_net_income(qc, base_date): diff --git a/streamlit_quant/strategy/magic_formula.py b/streamlit_quant/strategy/magic_formula.py index 55f8d8c..d3f0760 100644 --- a/streamlit_quant/strategy/magic_formula.py +++ b/streamlit_quant/strategy/magic_formula.py @@ -1,8 +1,6 @@ -import pandas as pd import numpy as np -import matplotlib.pyplot as plt -import seaborn as sns -import quantcommon +from streamlit_quant import quantcommon + # 마법 공식 포트폴리오. 밸류와 퀄리티의 조합. 조엘 그린블라트의 '마법공식' def get_magic_formula_top(count): diff --git a/streamlit_quant/strategy/momentum.py b/streamlit_quant/strategy/momentum.py index 05439db..8f66225 100644 --- a/streamlit_quant/strategy/momentum.py +++ b/streamlit_quant/strategy/momentum.py @@ -3,7 +3,7 @@ import matplotlib.pyplot as plt import seaborn as sns import statsmodels.api as sm import numpy as np -import quantcommon +from streamlit_quant import quantcommon def print_graph(values): diff --git a/streamlit_quant/strategy/quality.py b/streamlit_quant/strategy/quality.py index 28a6e2e..60e98a8 100644 --- a/streamlit_quant/strategy/quality.py +++ b/streamlit_quant/strategy/quality.py @@ -1,7 +1,8 @@ import numpy as np import matplotlib.pyplot as plt import seaborn as sns -import quantcommon +from streamlit_quant import quantcommon + # 퀄리티(우량주) 포트폴리오. 영업수익성이 높은 주식 def get_quality_top(count): diff --git a/streamlit_quant/strategy/value.py b/streamlit_quant/strategy/value.py index fd9c2c2..24a8e8c 100644 --- a/streamlit_quant/strategy/value.py +++ b/streamlit_quant/strategy/value.py @@ -1,6 +1,7 @@ import numpy as np -import quantcommon +from streamlit_quant import quantcommon + #가치주 포트폴리오. PER, PBR이 낮은 회사 20개 def get_value_top(count): diff --git a/streamlit_quant/super_quality.py b/streamlit_quant/super_quality.py new file mode 100644 index 0000000..76b967b --- /dev/null +++ b/streamlit_quant/super_quality.py @@ -0,0 +1,67 @@ +from datetime import datetime +import streamlit as st + +from strategy import f_score +import quantcommon + + +# st.write(""" +# '신F-스코어 3점 + 고GP/A 전략'을 '강환국 슈퍼 퀄리티 전략'이라 명명한다. +# 이 전략은 신F-스코어가 3점인 종목을 매수하되, GP/A로 순위를 매겨서 순위가 높은 종목만 매수하는 것이다. +# 이 경우 한국에서 수익이 어땠을지 분석해보자. +# 연도별로 신F-스코어 3점을 충족하는 종목은 600-700개였다.\n +# 신F-스코어 3점 기업 내에서도 GP/A가 높은 종목이 3점 종목 평균보다 CAGR 기준으로 3-4% 더 높았다. +# 반대로 GP/A가 낮은 종목의 수익률은 상대적으로 저조했다.\n\n +# --- +# 투자 전략: 강환국 슈퍼 퀄리티 전략 1.0\n +# 레벨: 초, 중급\n +# 스타일: 퀄리티\n +# 기대 CAGR: 약 20%\n +# 매수 전략: +# - 신F-스코어 3점 종목만 매수\n +# - 여기에 GP/A 순위를 부여, 순위 높은 20-30종목을 매수\n +# 매도 전략: 연 1회 리밸런싱\n\n\n +# --- +# 지금까지 소개한 거의 모든 전략에서 소형주 전략이 전체 주식 수익률보다 높았다. +# 시가총액 하위 20% 종목의 CAGR을 분석해보았다.\n\n +# --- +# 투자 전략: 강환국 슈퍼 퀄리티 전략 2.0\n +# 레벨: 초, 중급\n +# 스타일: 퀄리티\n +# 기대 CAGR: 20% 이상\n +# 매수 전략: +# 아래 조건을 만족하는 20-30종목 매수\n +# - 신F-스코어 3점 종목만 매수\n +# - 여기에 GP/A 순위를 부여, 순위 높은 종목만 매수\n +# - 단, 소형주(시가총액 최저 20%)만 매수\n +# 매도 전략: 연 1회 리밸런싱\n +# --- +# 소형주 중 신F-스코어가 3점인 종목을 찾아보니 2004-2016년 구간에 80-100개 종목이 남았다. +# 그 주식들을 통째로 매수해도 CAGR 34.55%를 벌수 있었다! +# 정말 상당한 수익이다. +# 이 종목들을 다 샀으면 총 1,159개 종목 중 14개가 파산했다.(1.2%) +# 또 1년간 마이너스 수익을 기록한 종목이 29.7%였다.\n +# 신F-스코어가 3점인 종목 중 GP/A가 높은 종목 위주로 매수했으면 (1) CAGR도 조금 개선되고 (2) 최상 30개 종목을 매수했을 경우 선택받은 종목 360개 중 파산한 기업은 단 1개였다. +# F-스코어와 GP/A는 엄청난 잠재력을 지닌 콤비네이션임이 분명하다. +# """) + +def get_last_year_end(): + # 현재 날짜 가져오기 (2025년 3월 16일 기준) + today = datetime.now() + + # 작년 연도 계산 + last_year = today.year - 1 + + # 작년 12월 31일 생성 + last_year_end = datetime(last_year, 12, 31) + + return last_year_end.date() + +st.write("투자 전략: 강환국 슈퍼 퀄리티 전략 2.0") + +date = get_last_year_end() +data = f_score.get_f_score(quantcommon.QuantCommon(), date) + +config = {} + +st.dataframe(data, column_config=config, use_container_width=True) diff --git a/streamlit_quant/pages/super_value_momentum.py b/streamlit_quant/super_value_momentum.py similarity index 100% rename from streamlit_quant/pages/super_value_momentum.py rename to streamlit_quant/super_value_momentum.py