From 679eb4fe0b327e161c4e07b35674b050a21c246b Mon Sep 17 00:00:00 2001 From: Ayuriel Date: Sat, 15 Mar 2025 01:24:46 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=ED=8C=8C=EC=9D=BC=20=EC=9D=B4=EB=A6=84?= =?UTF-8?q?=20=EB=B3=80=EA=B2=BD,=20=EB=B0=B1=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=20=EC=83=98=ED=94=8C=20=EC=B6=94=EA=B0=80,=20=EB=94=94?= =?UTF-8?q?=EB=A0=89=ED=86=A0=EB=A6=AC=20=ED=8C=A8=ED=82=A4=EC=A7=80?= =?UTF-8?q?=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 7 +++ quantcommon.py | 13 ++++++ streamlit_quant/__init__.py | 1 + {streamlit-quant => streamlit_quant}/app.py | 0 streamlit_quant/backtest/backtest-1.py | 46 +++++++++++++++++++ .../pages/crawling.py | 0 .../pages/super_quality.py | 0 .../pages/super_value_momentum.py | 0 .../src/current-financial-statements.py | 0 .../src/current-price.py | 0 .../src/current-stock.py | 0 streamlit_quant/strategy/__init__.py | 1 + .../strategy/all_value.py | 0 .../strategy/f_score.py | 1 - .../strategy/magic_formula.py | 0 .../strategy/momentum.py | 0 .../strategy/multi_factor.py | 17 ++----- .../strategy/quality.py | 0 .../strategy/value.py | 0 19 files changed, 71 insertions(+), 15 deletions(-) create mode 100644 streamlit_quant/__init__.py rename {streamlit-quant => streamlit_quant}/app.py (100%) create mode 100644 streamlit_quant/backtest/backtest-1.py rename {streamlit-quant => streamlit_quant}/pages/crawling.py (100%) rename {streamlit-quant => streamlit_quant}/pages/super_quality.py (100%) rename {streamlit-quant => streamlit_quant}/pages/super_value_momentum.py (100%) rename {streamlit-quant => streamlit_quant}/src/current-financial-statements.py (100%) rename {streamlit-quant => streamlit_quant}/src/current-price.py (100%) rename {streamlit-quant => streamlit_quant}/src/current-stock.py (100%) create mode 100644 streamlit_quant/strategy/__init__.py rename streamlit-quant/strategy/all-value.py => streamlit_quant/strategy/all_value.py (100%) rename streamlit-quant/strategy/f-score.py => streamlit_quant/strategy/f_score.py (95%) rename streamlit-quant/strategy/magic-formula.py => streamlit_quant/strategy/magic_formula.py (100%) rename {streamlit-quant => streamlit_quant}/strategy/momentum.py (100%) rename streamlit-quant/strategy/multi-factor.py => streamlit_quant/strategy/multi_factor.py (96%) rename {streamlit-quant => streamlit_quant}/strategy/quality.py (100%) rename {streamlit-quant => streamlit_quant}/strategy/value.py (100%) diff --git a/README.md b/README.md index b451cc3..45ea151 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,9 @@ # 실행 streamlit run .\streamlit-quant\app.py --server.port 20000 + +# pre- +Go to Build Tools for Visual Studio 2017 +Select free download under Visual Studio Community 2017. This will download the installer. Run the installer. +Select what you need under workload tab: +a. Under Windows, there are three choices. Only check Desktop development with C++. +b. Under Web & Cloud, there are seven choices. Only check Python development (I believe this is optional, but I have done it). \ No newline at end of file diff --git a/quantcommon.py b/quantcommon.py index 8b3f5b7..2df5794 100644 --- a/quantcommon.py +++ b/quantcommon.py @@ -69,6 +69,19 @@ class QuantCommon: return price_list + def get_price_list_by_code(self, codes): + engine = self.create_engine() + + try: + price_list = pd.read_sql(f""" + select * from kor_price + where 종목코드 in ({codes}); + """, con=engine) + finally: + engine.dispose() + + return price_list + def get_fs_list(self): engine = self.create_engine() diff --git a/streamlit_quant/__init__.py b/streamlit_quant/__init__.py new file mode 100644 index 0000000..04bd080 --- /dev/null +++ b/streamlit_quant/__init__.py @@ -0,0 +1 @@ +__all__ = ['backtest', 'strategy'] \ No newline at end of file diff --git a/streamlit-quant/app.py b/streamlit_quant/app.py similarity index 100% rename from streamlit-quant/app.py rename to streamlit_quant/app.py diff --git a/streamlit_quant/backtest/backtest-1.py b/streamlit_quant/backtest/backtest-1.py new file mode 100644 index 0000000..9b62d7a --- /dev/null +++ b/streamlit_quant/backtest/backtest-1.py @@ -0,0 +1,46 @@ +import bt +import matplotlib.pyplot as plt + +import pandas as pd + +import quantcommon +import streamlit_quant.strategy.multi_factor as multi_factor + + +qc = quantcommon.QuantCommon() +mf = multi_factor.get_multi_factor_top(qc, 20) + +codes = ','.join(mf['종목코드'].array) +price = qc.get_price_list_by_code(codes) + +# price = price.set_index(['날짜']) +# price.rename(columns={"날짜": "Date"}) +price["Date"] = pd.to_datetime(price["날짜"]) + +pivot_df = price.pivot(index="Date", columns="종목코드", values="종가") + +# print(pivot_df.tail) + +strategy = bt.Strategy("Asset_EW", [ + bt.algos.SelectAll(), # 모든 데이터 사용 + bt.algos.WeighEqually(), # 동일 비중 투자 + bt.algos.RunMonthly(), # 매 월말 리밸런싱 + bt.algos.Rebalance() # 계산된 비중에 따라 리밸런싱 +]) + +# 가격 데이터 중 시작 시점이 모두 다르므로, dropna() 함수를 통해 NA를 모두 제거하여 시작 시점을 맞춤 +pivot_df.dropna(inplace=True) + +# 백테스트 생성 +backtest = bt.Backtest(strategy, pivot_df) + +# 백테스트 실행 +result = bt.run(backtest) +# prices: 누적 수익률이 데이터프레임 형태로 나타나며, 시작 시점을 100으로 환산하여 계산 +# to_returns: 수익률 계산 +# print(result.prices.to_returns()) + +result.plot(figsize=(10, 6), legend=False) +plt.show() + +result.display() \ No newline at end of file diff --git a/streamlit-quant/pages/crawling.py b/streamlit_quant/pages/crawling.py similarity index 100% rename from streamlit-quant/pages/crawling.py rename to streamlit_quant/pages/crawling.py diff --git a/streamlit-quant/pages/super_quality.py b/streamlit_quant/pages/super_quality.py similarity index 100% rename from streamlit-quant/pages/super_quality.py rename to streamlit_quant/pages/super_quality.py diff --git a/streamlit-quant/pages/super_value_momentum.py b/streamlit_quant/pages/super_value_momentum.py similarity index 100% rename from streamlit-quant/pages/super_value_momentum.py rename to streamlit_quant/pages/super_value_momentum.py diff --git a/streamlit-quant/src/current-financial-statements.py b/streamlit_quant/src/current-financial-statements.py similarity index 100% rename from streamlit-quant/src/current-financial-statements.py rename to streamlit_quant/src/current-financial-statements.py diff --git a/streamlit-quant/src/current-price.py b/streamlit_quant/src/current-price.py similarity index 100% rename from streamlit-quant/src/current-price.py rename to streamlit_quant/src/current-price.py diff --git a/streamlit-quant/src/current-stock.py b/streamlit_quant/src/current-stock.py similarity index 100% rename from streamlit-quant/src/current-stock.py rename to streamlit_quant/src/current-stock.py diff --git a/streamlit_quant/strategy/__init__.py b/streamlit_quant/strategy/__init__.py new file mode 100644 index 0000000..cb7180d --- /dev/null +++ b/streamlit_quant/strategy/__init__.py @@ -0,0 +1 @@ +__all__ = ['multi_factor'] \ No newline at end of file diff --git a/streamlit-quant/strategy/all-value.py b/streamlit_quant/strategy/all_value.py similarity index 100% rename from streamlit-quant/strategy/all-value.py rename to streamlit_quant/strategy/all_value.py diff --git a/streamlit-quant/strategy/f-score.py b/streamlit_quant/strategy/f_score.py similarity index 95% rename from streamlit-quant/strategy/f-score.py rename to streamlit_quant/strategy/f_score.py index 64f5393..66b2fc6 100644 --- a/streamlit-quant/strategy/f-score.py +++ b/streamlit_quant/strategy/f_score.py @@ -1,5 +1,4 @@ import pandas as pd -import numpy as np import quantcommon # DB 연결 diff --git a/streamlit-quant/strategy/magic-formula.py b/streamlit_quant/strategy/magic_formula.py similarity index 100% rename from streamlit-quant/strategy/magic-formula.py rename to streamlit_quant/strategy/magic_formula.py diff --git a/streamlit-quant/strategy/momentum.py b/streamlit_quant/strategy/momentum.py similarity index 100% rename from streamlit-quant/strategy/momentum.py rename to streamlit_quant/strategy/momentum.py diff --git a/streamlit-quant/strategy/multi-factor.py b/streamlit_quant/strategy/multi_factor.py similarity index 96% rename from streamlit-quant/strategy/multi-factor.py rename to streamlit_quant/strategy/multi_factor.py index e5a3c57..a0d9139 100644 --- a/streamlit-quant/strategy/multi-factor.py +++ b/streamlit_quant/strategy/multi_factor.py @@ -4,14 +4,11 @@ import statsmodels.api as sm from scipy.stats import zscore import matplotlib.pyplot as plt import seaborn as sns -import quantcommon # 멀티 팩터 포트폴리오. # 퀄리티: 자기자본이익률(ROE), 매출총이익(GPA), 영업활동현금흐름(CFO) # 밸류: PER, PBR, PSR, PCR, DY # 모멘텀: 12개월 수익률, K-Ratio -engine = quantcommon.QuantCommon().create_engine() - # 각 섹터별 아웃라이어를 제거한 후 순위와 z-score를 구하는 함수 def col_clean(df, cutoff=0.01, asc=False): @@ -45,8 +42,7 @@ def plot_rank(df): plt.show() -def get_multi_factor_top(count): - qc = quantcommon.QuantCommon() +def get_multi_factor_top(qc, count): ticker_list = qc.get_ticker_list() fs_list = qc.get_fs_list() value_list = qc.get_value_list() @@ -220,7 +216,7 @@ def get_multi_factor_top(count): # 기본 테이블(data_bind)과 합침 port_qvm = data_bind.merge(data_bind_final_sum, on='종목코드') # 최종 z-score의 합(qvm) 기준 순위가 20위 이내인 경우 투자 종목에 해당하니 Y로 표시, 나머진 N - port_qvm['invest'] = np.where(port_qvm['qvm'].rank() <= 20, 'Y', 'N') + port_qvm['invest'] = np.where(port_qvm['qvm'].rank() <= count, 'Y', 'N') # round()는 DataFrame 객체 내의 요소를 반올림하는 메서드 return port_qvm[port_qvm['invest'] == 'Y'].round(4) @@ -252,11 +248,4 @@ def get_multi_factor_top(count): # hist_momentum['rank'] = hist_momentum.groupby('variable')['value'].rank(ascending = False) # plot_rank(hist_momentum) # - # port_qvm[port_qvm['invest'] == 'Y']['종목코드'].to_excel('model.xlsx', index=False) - - -if __name__ == '__main__': - top = get_multi_factor_top(20) - # head() 상위 n개 반환. 기본값은 5 - print(top.head()) - top['종목코드'].to_excel('model.xlsx', index=False) \ No newline at end of file + # port_qvm[port_qvm['invest'] == 'Y']['종목코드'].to_excel('model.xlsx', index=False) \ No newline at end of file diff --git a/streamlit-quant/strategy/quality.py b/streamlit_quant/strategy/quality.py similarity index 100% rename from streamlit-quant/strategy/quality.py rename to streamlit_quant/strategy/quality.py diff --git a/streamlit-quant/strategy/value.py b/streamlit_quant/strategy/value.py similarity index 100% rename from streamlit-quant/strategy/value.py rename to streamlit_quant/strategy/value.py