Spaces:
Sleeping
Sleeping
Update streamlit_app.py
Browse files- streamlit_app.py +83 -56
streamlit_app.py
CHANGED
|
@@ -1,78 +1,105 @@
|
|
| 1 |
import streamlit as st
|
| 2 |
import yfinance as yf
|
| 3 |
import FinanceDataReader as fdr
|
|
|
|
| 4 |
|
| 5 |
# 1. ํ์ด์ง ์ค์
|
| 6 |
st.set_page_config(page_title="Pocket Quant", page_icon="๐", layout="centered")
|
|
|
|
|
|
|
| 7 |
|
| 8 |
-
|
| 9 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
|
| 11 |
-
#
|
| 12 |
@st.cache_data
|
| 13 |
def get_stock_list():
|
| 14 |
-
|
| 15 |
-
df = fdr.StockListing('KRX')
|
| 16 |
-
return df
|
| 17 |
|
| 18 |
-
|
| 19 |
-
with st.spinner('ํ๊ตญ ์ฃผ์ "์ ํ๋ฒํธ๋ถ"๋ฅผ ๋ถ๋ฌ์ค๋ ์ค...'):
|
| 20 |
df_krx = get_stock_list()
|
| 21 |
|
| 22 |
-
#
|
| 23 |
def search_ticker(input_text):
|
| 24 |
-
|
| 25 |
-
if input_text.isascii():
|
| 26 |
-
return input_text.upper()
|
| 27 |
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
if res.empty:
|
| 35 |
-
return None
|
| 36 |
-
|
| 37 |
-
# ์ฐพ์์ผ๋ฉด ํฐ์ปค ์ฝ๋ ๋ณํ
|
| 38 |
-
code = res.iloc[0]['Code']
|
| 39 |
-
market = res.iloc[0]['Market']
|
| 40 |
-
|
| 41 |
-
# ์ผํ ํ์ด๋ธ์ค์ฉ ์ ๋ฏธ์ฌ ๋ถ์ด๊ธฐ (.KS ์ฝ์คํผ, .KQ ์ฝ์ค๋ฅ)
|
| 42 |
-
if market == 'KOSPI':
|
| 43 |
-
return f"{code}.KS"
|
| 44 |
-
elif market == 'KOSDAQ':
|
| 45 |
-
return f"{code}.KQ"
|
| 46 |
-
else:
|
| 47 |
-
return code # ๊ธฐํ
|
| 48 |
|
| 49 |
-
#
|
| 50 |
-
user_input = st.text_input("์ข
๋ชฉ๋ช
|
| 51 |
|
| 52 |
-
|
| 53 |
-
if st.button("๐ ๋ถ์ ์คํ", use_container_width=True):
|
| 54 |
-
|
| 55 |
-
# ํ๊ธ ์ด๋ฆ์ ํฐ์ปค๋ก ๋ณํ!
|
| 56 |
ticker = search_ticker(user_input)
|
| 57 |
|
| 58 |
if ticker:
|
| 59 |
-
st.
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
if not hist.empty:
|
| 66 |
-
curr = hist['Close'].iloc[-1]
|
| 67 |
-
prev = hist['Close'].iloc[-2]
|
| 68 |
-
pct = ((curr - prev) / prev) * 100
|
| 69 |
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 77 |
else:
|
| 78 |
-
st.error(f"
|
|
|
|
| 1 |
import streamlit as st
|
| 2 |
import yfinance as yf
|
| 3 |
import FinanceDataReader as fdr
|
| 4 |
+
from huggingface_hub import InferenceClient
|
| 5 |
|
| 6 |
# 1. ํ์ด์ง ์ค์
|
| 7 |
st.set_page_config(page_title="Pocket Quant", page_icon="๐", layout="centered")
|
| 8 |
+
st.title("๐จ๐ณ Qwen ํฌ์ ์๋ฌธ๊ฐ")
|
| 9 |
+
st.caption("Alibaba Qwen2.5-72B ๋ชจ๋ธ์ด ๋ถ์ํฉ๋๋ค. (Zero Cost)")
|
| 10 |
|
| 11 |
+
# 2. ํ๊น
ํ์ด์ค ํ ํฐ & ํด๋ผ์ด์ธํธ ์ค์
|
| 12 |
+
# Secrets์ HF_TOKEN์ด ์์ผ๋ฉด ์๋ฌ ๋ฐฉ์ง
|
| 13 |
+
if "HF_TOKEN" in st.secrets:
|
| 14 |
+
client = InferenceClient(api_key=st.secrets["HF_TOKEN"])
|
| 15 |
+
else:
|
| 16 |
+
st.error("๐จ ์ค์ ์ค๋ฅ: Settings > Secrets์ 'HF_TOKEN'์ ๋ฃ์ด์ฃผ์ธ์!")
|
| 17 |
+
st.stop()
|
| 18 |
|
| 19 |
+
# 3. ์ฃผ์ ๋ฐ์ดํฐ ๋ก๋ฉ
|
| 20 |
@st.cache_data
|
| 21 |
def get_stock_list():
|
| 22 |
+
return fdr.StockListing('KRX')
|
|
|
|
|
|
|
| 23 |
|
| 24 |
+
with st.spinner('์ ํ๋ฒํธ๋ถ ๋ค์ง๋ ์ค...'):
|
|
|
|
| 25 |
df_krx = get_stock_list()
|
| 26 |
|
| 27 |
+
# 4. ์ข
๋ชฉ ๊ฒ์ ํจ์
|
| 28 |
def search_ticker(input_text):
|
| 29 |
+
if input_text.isascii(): return input_text.upper()
|
|
|
|
|
|
|
| 30 |
|
| 31 |
+
res = df_krx[df_krx['Name'] == input_text]
|
| 32 |
+
if res.empty: return None
|
| 33 |
+
|
| 34 |
+
code = res.iloc[0]['Code']
|
| 35 |
+
market = res.iloc[0]['Market']
|
| 36 |
+
return f"{code}.KS" if market == 'KOSPI' else f"{code}.KQ"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 37 |
|
| 38 |
+
# 5. UI ๋ฐ ์คํ
|
| 39 |
+
user_input = st.text_input("์ข
๋ชฉ๋ช
(์: ์ผ์ฑ์ ์, ์นด์นด์ค, TSLA)", "์ผ์ฑ์ ์")
|
| 40 |
|
| 41 |
+
if st.button("๐ Qwen์๊ฒ ๋ฌผ์ด๋ณด๊ธฐ", use_container_width=True):
|
|
|
|
|
|
|
|
|
|
| 42 |
ticker = search_ticker(user_input)
|
| 43 |
|
| 44 |
if ticker:
|
| 45 |
+
with st.spinner(f"๐ 1๋จ๊ณ: '{ticker}' ์์ธ ์กฐํ ์ค..."):
|
| 46 |
+
try:
|
| 47 |
+
# ๋ฐ์ดํฐ ์์ง
|
| 48 |
+
stock = yf.Ticker(ticker)
|
| 49 |
+
hist = stock.history(period="1mo")
|
| 50 |
+
info = stock.info
|
|
|
|
|
|
|
|
|
|
|
|
|
| 51 |
|
| 52 |
+
if not hist.empty:
|
| 53 |
+
# ๊ธฐ๋ณธ ์ฐจํธ ํ์
|
| 54 |
+
curr = hist['Close'].iloc[-1]
|
| 55 |
+
start = hist['Close'].iloc[0]
|
| 56 |
+
change = ((curr - start) / start) * 100
|
| 57 |
+
|
| 58 |
+
st.metric("ํ์ฌ ์ฃผ๊ฐ", f"{curr:,.0f}์", f"{change:.2f}% (1๋ฌ)")
|
| 59 |
+
st.line_chart(hist['Close'])
|
| 60 |
+
|
| 61 |
+
# --- Qwen AI ํํธ ---
|
| 62 |
+
with st.spinner("๐ 2๋จ๊ณ: ํ์ฌ(Qwen)์ด ์ฐจํธ๋ฅผ ํด์ํ๋ ์ค..."):
|
| 63 |
+
|
| 64 |
+
# ํ๋กฌํํธ ์์ฑ
|
| 65 |
+
prompt = f"""
|
| 66 |
+
๋น์ ์ ๋์ฒ ํ ์ฃผ์ ํฌ์ ์ ๋ฌธ๊ฐ์
๋๋ค. ์๋ ๋ฐ์ดํฐ๋ฅผ ๋ถ์ํด์ ํ๊ตญ์ด๋ก ๋ณด๊ณ ์๋ฅผ ์จ์ฃผ์ธ์.
|
| 67 |
+
|
| 68 |
+
[์ข
๋ชฉ ๋ฐ์ดํฐ]
|
| 69 |
+
- ์ข
๋ชฉ๋ช
: {user_input} ({ticker})
|
| 70 |
+
- ํ์ฌ๊ฐ: {curr:,.0f}
|
| 71 |
+
- 1๋ฌ ๋ณ๋๋ฅ : {change:.2f}%
|
| 72 |
+
- 52์ฃผ ์ต๊ณ ๊ฐ: {info.get('fiftyTwoWeekHigh', 'N/A')}
|
| 73 |
+
- 52์ฃผ ์ต์ ๊ฐ: {info.get('fiftyTwoWeekLow', 'N/A')}
|
| 74 |
+
|
| 75 |
+
[๋ถ์ ์์ฒญ]
|
| 76 |
+
1. ์ต๊ทผ 1๋ฌ๊ฐ์ ์ถ์ธ๋ฅผ ํ ๋ฌธ์ฅ์ผ๋ก ์์ฝํ์ธ์.
|
| 77 |
+
2. ํ์ฌ ๊ฐ๊ฒฉ์ด ๊ณ ์ ๋๋น ์ด๋ค ์์น์ธ์ง ์ค๋ช
ํ์ธ์.
|
| 78 |
+
3. ํฌ์ ๊ด์ (๋งค์/๋งค๋/๊ด๋ง)์ ์์งํ๊ฒ ์ ์ํ๊ณ ์ด์ ๋ฅผ ๋ง๋ถ์ด์ธ์.
|
| 79 |
+
|
| 80 |
+
๋งํฌ๋ 'ํด์์ฒด'๋ฅผ ์ฐ๊ณ , ์ด๋ชจ์ง๋ฅผ ์ ์ ํ ์ฌ์ฉํ์ธ์.
|
| 81 |
+
"""
|
| 82 |
+
|
| 83 |
+
# Qwen ํธ์ถ (์ฑํ
๋ฉ์์ง ํ์)
|
| 84 |
+
messages = [
|
| 85 |
+
{"role": "system", "content": "You are a helpful financial analyst."},
|
| 86 |
+
{"role": "user", "content": prompt}
|
| 87 |
+
]
|
| 88 |
+
|
| 89 |
+
# ์คํธ๋ฆฌ๋ฐ ๋ฐฉ์์ผ๋ก ์ถ๋ ฅ (ํ์ ์น๋ ๊ฒ์ฒ๋ผ ๋์ด)
|
| 90 |
+
stream = client.chat.completions.create(
|
| 91 |
+
model="Qwen/Qwen2.5-72B-Instruct",
|
| 92 |
+
messages=messages,
|
| 93 |
+
max_tokens=500,
|
| 94 |
+
stream=True
|
| 95 |
+
)
|
| 96 |
+
|
| 97 |
+
st.subheader("๐ Qwen์ ๋ถ์ ๋ฆฌํฌํธ")
|
| 98 |
+
st.write_stream(stream)
|
| 99 |
+
|
| 100 |
+
else:
|
| 101 |
+
st.error("๋ฐ์ดํฐ๊ฐ ์์ด์. ์์ฅํ์ง ๋๊ฑฐ๋ ํฐ์ปค๊ฐ ํ๋ ธ์ ์๋?")
|
| 102 |
+
except Exception as e:
|
| 103 |
+
st.error(f"์๋ฌ๊ฐ ๋ฌ์ต๋๋ค: {e}")
|
| 104 |
else:
|
| 105 |
+
st.error(f"'{user_input}'? ๊ทธ๋ฐ ์ฃผ์์ ํ๊ตญ์ ์๋๋ฐ์.")
|