Update app.py
Browse files
app.py
CHANGED
|
@@ -33,10 +33,6 @@ TAIWAN_STOCKS = {
|
|
| 33 |
'譜瑞-KY': '4966.TWO',
|
| 34 |
'貿聯-KY': '3665.TW',
|
| 35 |
'騰雲': '6870.TWO',
|
| 36 |
-
'緯軟': '4953.TWO',
|
| 37 |
-
'旺宏': '2337.TW',
|
| 38 |
-
'順德': '2351.TW',
|
| 39 |
-
'南亞科': '2408.TW',
|
| 40 |
'穩懋': '3105.TWO'
|
| 41 |
}
|
| 42 |
|
|
@@ -58,11 +54,7 @@ INDUSTRY_MAPPING = {
|
|
| 58 |
'1101.TW': '營建',
|
| 59 |
'4966.TWO': '高速傳輸',
|
| 60 |
'3665.TW': '連接器',
|
| 61 |
-
'2337.TW': 'NFLASH',
|
| 62 |
-
'2408.TW': 'DRAM',
|
| 63 |
-
'2351.TW': '車用導線架',
|
| 64 |
'6870.TWO': '軟體整合',
|
| 65 |
-
'4953.TWO': '軟體外包',
|
| 66 |
'3105.TWO': 'PA功率'
|
| 67 |
}
|
| 68 |
|
|
@@ -640,7 +632,8 @@ def update_taiex_prediction(predict_days):
|
|
| 640 |
# --- 修改結束 ---
|
| 641 |
|
| 642 |
# 預測結果卡片 (維持不變)
|
| 643 |
-
|
|
|
|
| 644 |
arrow = '📈' if change_pct >= 0 else '📉'
|
| 645 |
|
| 646 |
result_card = html.Div([
|
|
@@ -718,13 +711,15 @@ def update_stock_info(selected_stock):
|
|
| 718 |
# 找出股票中文名稱
|
| 719 |
stock_name = [name for name, symbol in TAIWAN_STOCKS.items() if symbol == selected_stock][0]
|
| 720 |
|
| 721 |
-
|
|
|
|
|
|
|
| 722 |
|
| 723 |
return html.Div([
|
| 724 |
html.Div([
|
| 725 |
html.H3(f"{stock_name} ({selected_stock})", style={'margin': '0'}),
|
| 726 |
html.H2(f"${current_price:.2f}", style={'margin': '5px 0', 'color': color}),
|
| 727 |
-
html.P(f"{
|
| 728 |
style={'margin': '0', 'color': color, 'font-weight': 'bold'})
|
| 729 |
], style={
|
| 730 |
'background': 'white',
|
|
@@ -765,13 +760,16 @@ def update_price_chart(selected_stock, period, chart_type):
|
|
| 765 |
stock_name = [name for name, symbol in TAIWAN_STOCKS.items() if symbol == selected_stock][0]
|
| 766 |
|
| 767 |
if chart_type == 'candlestick':
|
|
|
|
| 768 |
fig = go.Figure(data=go.Candlestick(
|
| 769 |
x=data.index,
|
| 770 |
open=data['Open'],
|
| 771 |
high=data['High'],
|
| 772 |
low=data['Low'],
|
| 773 |
close=data['Close'],
|
| 774 |
-
name=stock_name
|
|
|
|
|
|
|
| 775 |
))
|
| 776 |
else:
|
| 777 |
fig = px.line(data, y='Close', title=f'{stock_name} 股價走勢')
|
|
@@ -804,13 +802,14 @@ def update_rsi_chart(selected_stock, period):
|
|
| 804 |
|
| 805 |
fig = go.Figure()
|
| 806 |
fig.add_trace(go.Scatter(x=data.index, y=data['RSI'], mode='lines', name='RSI', line=dict(color='purple', width=2)))
|
| 807 |
-
|
| 808 |
-
fig.add_hline(y=
|
|
|
|
| 809 |
fig.add_hline(y=50, line_dash="dot", line_color="gray", annotation_text="中線(50)")
|
| 810 |
|
| 811 |
# 添加超買超賣區域背景
|
| 812 |
-
fig.add_hrect(y0=70, y1=100, fillcolor="
|
| 813 |
-
fig.add_hrect(y0=0, y1=30, fillcolor="
|
| 814 |
|
| 815 |
fig.update_layout(
|
| 816 |
title='RSI 相對強弱指標',
|
|
@@ -840,12 +839,14 @@ def update_advanced_technical_chart(indicator, selected_stock, period):
|
|
| 840 |
if indicator == 'RSI':
|
| 841 |
fig = go.Figure()
|
| 842 |
fig.add_trace(go.Scatter(x=data.index, y=data['RSI'], mode='lines', name='RSI', line=dict(color='purple', width=2)))
|
| 843 |
-
|
| 844 |
-
fig.add_hline(y=
|
|
|
|
| 845 |
fig.add_hline(y=50, line_dash="dot", line_color="gray", annotation_text="中線(50)")
|
| 846 |
-
|
| 847 |
-
|
| 848 |
-
fig.add_hrect(y0=
|
|
|
|
| 849 |
|
| 850 |
fig.update_layout(
|
| 851 |
title=f'{stock_name} - RSI 相對強弱指標',
|
|
@@ -891,7 +892,8 @@ def update_advanced_technical_chart(indicator, selected_stock, period):
|
|
| 891 |
), row=2, col=1)
|
| 892 |
|
| 893 |
# 3. Histogram 柱狀圖
|
| 894 |
-
|
|
|
|
| 895 |
fig.add_trace(go.Bar(
|
| 896 |
x=data.index,
|
| 897 |
y=data['MACD_Histogram'],
|
|
@@ -962,13 +964,15 @@ def update_advanced_technical_chart(indicator, selected_stock, period):
|
|
| 962 |
line=dict(color='red', width=2)), row=2, col=1)
|
| 963 |
|
| 964 |
# KD指標參考線
|
| 965 |
-
|
| 966 |
-
fig.add_hline(y=
|
|
|
|
| 967 |
fig.add_hline(y=50, line_dash="dot", line_color="gray", annotation_text="中線(50)", row=2, col=1)
|
| 968 |
|
| 969 |
# 超買超賣區域
|
| 970 |
-
|
| 971 |
-
fig.add_hrect(y0=
|
|
|
|
| 972 |
|
| 973 |
fig.update_layout(
|
| 974 |
title=f'{stock_name} - KD 隨機指標 (9,3,3)',
|
|
@@ -991,13 +995,15 @@ def update_advanced_technical_chart(indicator, selected_stock, period):
|
|
| 991 |
line=dict(color='purple', width=2)), row=2, col=1)
|
| 992 |
|
| 993 |
# 威廉指標參考線
|
| 994 |
-
|
| 995 |
-
fig.add_hline(y=-
|
|
|
|
| 996 |
fig.add_hline(y=-50, line_dash="dot", line_color="gray", annotation_text="中線(-50)", row=2, col=1)
|
| 997 |
|
| 998 |
# 超買超賣區域
|
| 999 |
-
|
| 1000 |
-
fig.add_hrect(y0=-
|
|
|
|
| 1001 |
|
| 1002 |
fig.update_layout(
|
| 1003 |
title=f'{stock_name} - 威廉指標 %R (14日)',
|
|
@@ -1172,12 +1178,13 @@ def update_analysis_text(selected_stock, period):
|
|
| 1172 |
d_current = data['D'].iloc[-1] if not pd.isna(data['D'].iloc[-1]) else 50
|
| 1173 |
|
| 1174 |
# 技術面分析
|
|
|
|
| 1175 |
technical_text = html.Div([
|
| 1176 |
html.P([
|
| 1177 |
html.Strong("價格趨勢:"),
|
| 1178 |
f"近期{period}期間內,{stock_name}呈現",
|
| 1179 |
html.Span(f"{'上漲' if price_change > 5 else '下跌' if price_change < -5 else '盤整'}",
|
| 1180 |
-
style={'color': '
|
| 1181 |
f"走勢,累計變動{price_change:+.1f}%。"
|
| 1182 |
]),
|
| 1183 |
html.P([
|
|
@@ -1185,7 +1192,7 @@ def update_analysis_text(selected_stock, period):
|
|
| 1185 |
f"目前為{rsi_current:.1f},",
|
| 1186 |
html.Span(
|
| 1187 |
"處於超買區間" if rsi_current > 70 else "處於超賣區間" if rsi_current < 30 else "在正常範圍內",
|
| 1188 |
-
style={'color': '
|
| 1189 |
),
|
| 1190 |
"。"
|
| 1191 |
]),
|
|
@@ -1194,7 +1201,7 @@ def update_analysis_text(selected_stock, period):
|
|
| 1194 |
f"MACD線({macd_current:.3f})",
|
| 1195 |
html.Span(
|
| 1196 |
"高於" if macd_current > macd_signal_current else "低於",
|
| 1197 |
-
style={'color': '
|
| 1198 |
),
|
| 1199 |
f"信號線({macd_signal_current:.3f}),",
|
| 1200 |
f"顯示{'多頭' if macd_current > macd_signal_current else '空頭'}格局。"
|
|
@@ -1204,7 +1211,7 @@ def update_analysis_text(selected_stock, period):
|
|
| 1204 |
f"股價位於通道",
|
| 1205 |
html.Span(
|
| 1206 |
"上半部" if bb_position > 0.8 else "下半部" if bb_position < 0.2 else "中段",
|
| 1207 |
-
style={'color': '
|
| 1208 |
),
|
| 1209 |
f"({bb_position*100:.0f}%),",
|
| 1210 |
f"{'壓力較大' if bb_position > 0.8 else '支撐較強' if bb_position < 0.2 else '整理格局'}。"
|
|
@@ -1214,12 +1221,12 @@ def update_analysis_text(selected_stock, period):
|
|
| 1214 |
f"K值({k_current:.1f})",
|
| 1215 |
html.Span(
|
| 1216 |
"高於" if k_current > d_current else "低於",
|
| 1217 |
-
style={'color': '
|
| 1218 |
),
|
| 1219 |
f"D值({d_current:.1f}),",
|
| 1220 |
html.Span(
|
| 1221 |
"超買警戒" if k_current > 80 else "超賣關注" if k_current < 20 else "正常區間",
|
| 1222 |
-
style={'color': '
|
| 1223 |
),
|
| 1224 |
"。"
|
| 1225 |
]),
|
|
@@ -1251,12 +1258,13 @@ def update_analysis_text(selected_stock, period):
|
|
| 1251 |
])
|
| 1252 |
|
| 1253 |
# 市場展望
|
|
|
|
| 1254 |
if price_change > 10:
|
| 1255 |
outlook_tone = "謹慎樂觀"
|
| 1256 |
-
outlook_color = "#
|
| 1257 |
elif price_change < -10:
|
| 1258 |
outlook_tone = "保守觀望"
|
| 1259 |
-
outlook_color = "#
|
| 1260 |
else:
|
| 1261 |
outlook_tone = "中性持平"
|
| 1262 |
outlook_color = "#ffc107"
|
|
@@ -1306,8 +1314,9 @@ def update_pmi_chart(selected_stock):
|
|
| 1306 |
return fig
|
| 1307 |
|
| 1308 |
# 定義PMI顏色 (50以上擴張,以下緊縮)
|
|
|
|
| 1309 |
def get_pmi_color(value):
|
| 1310 |
-
return '
|
| 1311 |
|
| 1312 |
colors = [get_pmi_color(value) for value in df['Index']]
|
| 1313 |
|
|
@@ -1330,14 +1339,15 @@ def update_pmi_chart(selected_stock):
|
|
| 1330 |
fig.add_hline(y=50, line_dash="dash", line_color="black", annotation_text="榮枯線(50)")
|
| 1331 |
|
| 1332 |
# 添加背景色區域
|
|
|
|
| 1333 |
fig.add_hrect(
|
| 1334 |
y0=50, y1=60,
|
| 1335 |
-
fillcolor="
|
| 1336 |
annotation_text="擴張區間", annotation_position="top left"
|
| 1337 |
)
|
| 1338 |
fig.add_hrect(
|
| 1339 |
y0=40, y1=50,
|
| 1340 |
-
fillcolor="
|
| 1341 |
annotation_text="緊縮區間", annotation_position="bottom left"
|
| 1342 |
)
|
| 1343 |
|
|
@@ -1468,7 +1478,8 @@ def update_comparison_analysis(selected_stocks, period):
|
|
| 1468 |
if comparison_data:
|
| 1469 |
table_rows = []
|
| 1470 |
for item in sorted(comparison_data, key=lambda x: x['return'], reverse=True):
|
| 1471 |
-
|
|
|
|
| 1472 |
table_rows.append(
|
| 1473 |
html.Tr([
|
| 1474 |
html.Td(item['name'], style={'font-weight': 'bold'}),
|
|
@@ -1509,6 +1520,7 @@ def update_sentiment_analysis(selected_stock):
|
|
| 1509 |
sentiment_score = np.random.uniform(30, 80) # 模擬情緒分數 0-100
|
| 1510 |
|
| 1511 |
# 建立情緒指標圓形圖
|
|
|
|
| 1512 |
gauge_fig = go.Figure(go.Indicator(
|
| 1513 |
mode = "gauge+number+delta",
|
| 1514 |
value = sentiment_score,
|
|
@@ -1517,11 +1529,11 @@ def update_sentiment_analysis(selected_stock):
|
|
| 1517 |
delta = {'reference': 50},
|
| 1518 |
gauge = {
|
| 1519 |
'axis': {'range': [None, 100]},
|
| 1520 |
-
'bar': {'color': "
|
| 1521 |
'steps': [
|
| 1522 |
-
{'range': [0, 30], 'color': "
|
| 1523 |
{'range': [30, 70], 'color': "lightgray"},
|
| 1524 |
-
{'range': [70, 100], 'color': "
|
| 1525 |
],
|
| 1526 |
'threshold': {
|
| 1527 |
'line': {'color': "red", 'width': 4},
|
|
@@ -1548,7 +1560,7 @@ def update_sentiment_analysis(selected_stock):
|
|
| 1548 |
html.P(news, style={
|
| 1549 |
'margin': '8px 0',
|
| 1550 |
'padding': '8px',
|
| 1551 |
-
'background': '#
|
| 1552 |
'border-radius': '5px',
|
| 1553 |
'border-left': '3px solid #17a2b8',
|
| 1554 |
'font-size': '13px'
|
|
|
|
| 33 |
'譜瑞-KY': '4966.TWO',
|
| 34 |
'貿聯-KY': '3665.TW',
|
| 35 |
'騰雲': '6870.TWO',
|
|
|
|
|
|
|
|
|
|
|
|
|
| 36 |
'穩懋': '3105.TWO'
|
| 37 |
}
|
| 38 |
|
|
|
|
| 54 |
'1101.TW': '營建',
|
| 55 |
'4966.TWO': '高速傳輸',
|
| 56 |
'3665.TW': '連接器',
|
|
|
|
|
|
|
|
|
|
| 57 |
'6870.TWO': '軟體整合',
|
|
|
|
| 58 |
'3105.TWO': 'PA功率'
|
| 59 |
}
|
| 60 |
|
|
|
|
| 632 |
# --- 修改結束 ---
|
| 633 |
|
| 634 |
# 預測結果卡片 (維持不變)
|
| 635 |
+
# 根據台股慣例修改顏色
|
| 636 |
+
color = 'red' if change_pct >= 0 else 'green'
|
| 637 |
arrow = '📈' if change_pct >= 0 else '📉'
|
| 638 |
|
| 639 |
result_card = html.Div([
|
|
|
|
| 711 |
# 找出股票中文名稱
|
| 712 |
stock_name = [name for name, symbol in TAIWAN_STOCKS.items() if symbol == selected_stock][0]
|
| 713 |
|
| 714 |
+
# 根據台股慣例修改顏色
|
| 715 |
+
color = 'red' if change >= 0 else 'green'
|
| 716 |
+
arrow = '▲' if change >= 0 else '▼'
|
| 717 |
|
| 718 |
return html.Div([
|
| 719 |
html.Div([
|
| 720 |
html.H3(f"{stock_name} ({selected_stock})", style={'margin': '0'}),
|
| 721 |
html.H2(f"${current_price:.2f}", style={'margin': '5px 0', 'color': color}),
|
| 722 |
+
html.P(f"{arrow} {change:+.2f} ({change_pct:+.2f}%)",
|
| 723 |
style={'margin': '0', 'color': color, 'font-weight': 'bold'})
|
| 724 |
], style={
|
| 725 |
'background': 'white',
|
|
|
|
| 760 |
stock_name = [name for name, symbol in TAIWAN_STOCKS.items() if symbol == selected_stock][0]
|
| 761 |
|
| 762 |
if chart_type == 'candlestick':
|
| 763 |
+
# 根據台股慣例修改顏色
|
| 764 |
fig = go.Figure(data=go.Candlestick(
|
| 765 |
x=data.index,
|
| 766 |
open=data['Open'],
|
| 767 |
high=data['High'],
|
| 768 |
low=data['Low'],
|
| 769 |
close=data['Close'],
|
| 770 |
+
name=stock_name,
|
| 771 |
+
increasing_line_color='red', # 上漲為紅色
|
| 772 |
+
decreasing_line_color='green' # 下跌為綠色
|
| 773 |
))
|
| 774 |
else:
|
| 775 |
fig = px.line(data, y='Close', title=f'{stock_name} 股價走勢')
|
|
|
|
| 802 |
|
| 803 |
fig = go.Figure()
|
| 804 |
fig.add_trace(go.Scatter(x=data.index, y=data['RSI'], mode='lines', name='RSI', line=dict(color='purple', width=2)))
|
| 805 |
+
# 根據台股慣例修改顏色
|
| 806 |
+
fig.add_hline(y=70, line_dash="dash", line_color="green", annotation_text="超買線(70)")
|
| 807 |
+
fig.add_hline(y=30, line_dash="dash", line_color="red", annotation_text="超賣線(30)")
|
| 808 |
fig.add_hline(y=50, line_dash="dot", line_color="gray", annotation_text="中線(50)")
|
| 809 |
|
| 810 |
# 添加超買超賣區域背景
|
| 811 |
+
fig.add_hrect(y0=70, y1=100, fillcolor="green", opacity=0.1, annotation_text="超買區")
|
| 812 |
+
fig.add_hrect(y0=0, y1=30, fillcolor="red", opacity=0.1, annotation_text="超賣區")
|
| 813 |
|
| 814 |
fig.update_layout(
|
| 815 |
title='RSI 相對強弱指標',
|
|
|
|
| 839 |
if indicator == 'RSI':
|
| 840 |
fig = go.Figure()
|
| 841 |
fig.add_trace(go.Scatter(x=data.index, y=data['RSI'], mode='lines', name='RSI', line=dict(color='purple', width=2)))
|
| 842 |
+
# 根據台股慣例修改顏色
|
| 843 |
+
fig.add_hline(y=70, line_dash="dash", line_color="green", annotation_text="超買線(70)")
|
| 844 |
+
fig.add_hline(y=30, line_dash="dash", line_color="red", annotation_text="超賣線(30)")
|
| 845 |
fig.add_hline(y=50, line_dash="dot", line_color="gray", annotation_text="中線(50)")
|
| 846 |
+
|
| 847 |
+
# 根據台股慣例修改顏色
|
| 848 |
+
fig.add_hrect(y0=70, y1=100, fillcolor="green", opacity=0.1)
|
| 849 |
+
fig.add_hrect(y0=0, y1=30, fillcolor="red", opacity=0.1)
|
| 850 |
|
| 851 |
fig.update_layout(
|
| 852 |
title=f'{stock_name} - RSI 相對強弱指標',
|
|
|
|
| 892 |
), row=2, col=1)
|
| 893 |
|
| 894 |
# 3. Histogram 柱狀圖
|
| 895 |
+
# 根據台股慣例修改顏色
|
| 896 |
+
colors = ['red' if x >= 0 else 'green' for x in data['MACD_Histogram']]
|
| 897 |
fig.add_trace(go.Bar(
|
| 898 |
x=data.index,
|
| 899 |
y=data['MACD_Histogram'],
|
|
|
|
| 964 |
line=dict(color='red', width=2)), row=2, col=1)
|
| 965 |
|
| 966 |
# KD指標參考線
|
| 967 |
+
# 根據台股慣例修改顏色
|
| 968 |
+
fig.add_hline(y=80, line_dash="dash", line_color="green", annotation_text="超買線(80)", row=2, col=1)
|
| 969 |
+
fig.add_hline(y=20, line_dash="dash", line_color="red", annotation_text="超賣線(20)", row=2, col=1)
|
| 970 |
fig.add_hline(y=50, line_dash="dot", line_color="gray", annotation_text="中線(50)", row=2, col=1)
|
| 971 |
|
| 972 |
# 超買超賣區域
|
| 973 |
+
# 根據台股慣例修改顏色
|
| 974 |
+
fig.add_hrect(y0=80, y1=100, fillcolor="green", opacity=0.1, row=2, col=1)
|
| 975 |
+
fig.add_hrect(y0=0, y1=20, fillcolor="red", opacity=0.1, row=2, col=1)
|
| 976 |
|
| 977 |
fig.update_layout(
|
| 978 |
title=f'{stock_name} - KD 隨機指標 (9,3,3)',
|
|
|
|
| 995 |
line=dict(color='purple', width=2)), row=2, col=1)
|
| 996 |
|
| 997 |
# 威廉指標參考線
|
| 998 |
+
# 根據台股慣例修改顏色
|
| 999 |
+
fig.add_hline(y=-20, line_dash="dash", line_color="green", annotation_text="超買線(-20)", row=2, col=1)
|
| 1000 |
+
fig.add_hline(y=-80, line_dash="dash", line_color="red", annotation_text="超賣線(-80)", row=2, col=1)
|
| 1001 |
fig.add_hline(y=-50, line_dash="dot", line_color="gray", annotation_text="中線(-50)", row=2, col=1)
|
| 1002 |
|
| 1003 |
# 超買超賣區域
|
| 1004 |
+
# 根據台股慣例修改顏色
|
| 1005 |
+
fig.add_hrect(y0=-20, y1=0, fillcolor="green", opacity=0.1, row=2, col=1)
|
| 1006 |
+
fig.add_hrect(y0=-100, y1=-80, fillcolor="red", opacity=0.1, row=2, col=1)
|
| 1007 |
|
| 1008 |
fig.update_layout(
|
| 1009 |
title=f'{stock_name} - 威廉指標 %R (14日)',
|
|
|
|
| 1178 |
d_current = data['D'].iloc[-1] if not pd.isna(data['D'].iloc[-1]) else 50
|
| 1179 |
|
| 1180 |
# 技術面分析
|
| 1181 |
+
# 根據台股慣例修改顏色
|
| 1182 |
technical_text = html.Div([
|
| 1183 |
html.P([
|
| 1184 |
html.Strong("價格趨勢:"),
|
| 1185 |
f"近期{period}期間內,{stock_name}呈現",
|
| 1186 |
html.Span(f"{'上漲' if price_change > 5 else '下跌' if price_change < -5 else '盤整'}",
|
| 1187 |
+
style={'color': 'red' if price_change > 5 else 'green' if price_change < -5 else 'orange', 'font-weight': 'bold'}),
|
| 1188 |
f"走勢,累計變動{price_change:+.1f}%。"
|
| 1189 |
]),
|
| 1190 |
html.P([
|
|
|
|
| 1192 |
f"目前為{rsi_current:.1f},",
|
| 1193 |
html.Span(
|
| 1194 |
"處於超買區間" if rsi_current > 70 else "處於超賣區間" if rsi_current < 30 else "在正常範圍內",
|
| 1195 |
+
style={'color': 'green' if rsi_current > 70 else 'red' if rsi_current < 30 else 'blue', 'font-weight': 'bold'}
|
| 1196 |
),
|
| 1197 |
"。"
|
| 1198 |
]),
|
|
|
|
| 1201 |
f"MACD線({macd_current:.3f})",
|
| 1202 |
html.Span(
|
| 1203 |
"高於" if macd_current > macd_signal_current else "低於",
|
| 1204 |
+
style={'color': 'red' if macd_current > macd_signal_current else 'green', 'font-weight': 'bold'}
|
| 1205 |
),
|
| 1206 |
f"信號線({macd_signal_current:.3f}),",
|
| 1207 |
f"顯示{'多頭' if macd_current > macd_signal_current else '空頭'}格局。"
|
|
|
|
| 1211 |
f"股價位於通道",
|
| 1212 |
html.Span(
|
| 1213 |
"上半部" if bb_position > 0.8 else "下半部" if bb_position < 0.2 else "中段",
|
| 1214 |
+
style={'color': 'green' if bb_position > 0.8 else 'red' if bb_position < 0.2 else 'blue', 'font-weight': 'bold'}
|
| 1215 |
),
|
| 1216 |
f"({bb_position*100:.0f}%),",
|
| 1217 |
f"{'壓力較大' if bb_position > 0.8 else '支撐較強' if bb_position < 0.2 else '整理格局'}。"
|
|
|
|
| 1221 |
f"K值({k_current:.1f})",
|
| 1222 |
html.Span(
|
| 1223 |
"高於" if k_current > d_current else "低於",
|
| 1224 |
+
style={'color': 'red' if k_current > d_current else 'green', 'font-weight': 'bold'}
|
| 1225 |
),
|
| 1226 |
f"D值({d_current:.1f}),",
|
| 1227 |
html.Span(
|
| 1228 |
"超買警戒" if k_current > 80 else "超賣關注" if k_current < 20 else "正常區間",
|
| 1229 |
+
style={'color': 'green' if k_current > 80 else 'red' if k_current < 20 else 'blue', 'font-weight': 'bold'}
|
| 1230 |
),
|
| 1231 |
"。"
|
| 1232 |
]),
|
|
|
|
| 1258 |
])
|
| 1259 |
|
| 1260 |
# 市場展望
|
| 1261 |
+
# 根據台股慣例修改顏色
|
| 1262 |
if price_change > 10:
|
| 1263 |
outlook_tone = "謹慎樂觀"
|
| 1264 |
+
outlook_color = "#dc3545"
|
| 1265 |
elif price_change < -10:
|
| 1266 |
outlook_tone = "保守觀望"
|
| 1267 |
+
outlook_color = "#28a745"
|
| 1268 |
else:
|
| 1269 |
outlook_tone = "中性持平"
|
| 1270 |
outlook_color = "#ffc107"
|
|
|
|
| 1314 |
return fig
|
| 1315 |
|
| 1316 |
# 定義PMI顏色 (50以上擴張,以下緊縮)
|
| 1317 |
+
# 根據台股慣例修改顏色
|
| 1318 |
def get_pmi_color(value):
|
| 1319 |
+
return 'red' if value >= 50 else 'green'
|
| 1320 |
|
| 1321 |
colors = [get_pmi_color(value) for value in df['Index']]
|
| 1322 |
|
|
|
|
| 1339 |
fig.add_hline(y=50, line_dash="dash", line_color="black", annotation_text="榮枯線(50)")
|
| 1340 |
|
| 1341 |
# 添加背景色區域
|
| 1342 |
+
# 根據台股慣例修改顏色
|
| 1343 |
fig.add_hrect(
|
| 1344 |
y0=50, y1=60,
|
| 1345 |
+
fillcolor="lightcoral", opacity=0.2,
|
| 1346 |
annotation_text="擴張區間", annotation_position="top left"
|
| 1347 |
)
|
| 1348 |
fig.add_hrect(
|
| 1349 |
y0=40, y1=50,
|
| 1350 |
+
fillcolor="lightgreen", opacity=0.2,
|
| 1351 |
annotation_text="緊縮區間", annotation_position="bottom left"
|
| 1352 |
)
|
| 1353 |
|
|
|
|
| 1478 |
if comparison_data:
|
| 1479 |
table_rows = []
|
| 1480 |
for item in sorted(comparison_data, key=lambda x: x['return'], reverse=True):
|
| 1481 |
+
# 根據台股慣例修改顏色
|
| 1482 |
+
color = 'red' if item['return'] > 0 else 'green'
|
| 1483 |
table_rows.append(
|
| 1484 |
html.Tr([
|
| 1485 |
html.Td(item['name'], style={'font-weight': 'bold'}),
|
|
|
|
| 1520 |
sentiment_score = np.random.uniform(30, 80) # 模擬情緒分數 0-100
|
| 1521 |
|
| 1522 |
# 建立情緒指標圓形圖
|
| 1523 |
+
# 根據台股慣例修改顏色
|
| 1524 |
gauge_fig = go.Figure(go.Indicator(
|
| 1525 |
mode = "gauge+number+delta",
|
| 1526 |
value = sentiment_score,
|
|
|
|
| 1529 |
delta = {'reference': 50},
|
| 1530 |
gauge = {
|
| 1531 |
'axis': {'range': [None, 100]},
|
| 1532 |
+
'bar': {'color': "darkred"},
|
| 1533 |
'steps': [
|
| 1534 |
+
{'range': [0, 30], 'color': "lightgreen"},
|
| 1535 |
{'range': [30, 70], 'color': "lightgray"},
|
| 1536 |
+
{'range': [70, 100], 'color': "lightcoral"}
|
| 1537 |
],
|
| 1538 |
'threshold': {
|
| 1539 |
'line': {'color': "red", 'width': 4},
|
|
|
|
| 1560 |
html.P(news, style={
|
| 1561 |
'margin': '8px 0',
|
| 1562 |
'padding': '8px',
|
| 1563 |
+
'background': '#f8f9fa',
|
| 1564 |
'border-radius': '5px',
|
| 1565 |
'border-left': '3px solid #17a2b8',
|
| 1566 |
'font-size': '13px'
|