第三章:指数实时监控看板
说实话,做量化交易这么多年,我最大的体会就是——数据看板不是用来好看的,是用来救命的。
记得2021年5月那次暴跌吗?比特币从58000一路砸到30000,恐慌指数从80直接干到10。如果你当时盯着一个实时更新的看板,看到阈值告警闪红,你至少能少亏30%。
今天我就手把手教你,用Python搭建一个真正能用的恐慌贪婪指数监控看板。我们用两种框架:Streamlit(适合快速原型)和Dash(适合生产环境)。
3.1 看板的核心功能设计
先别急着写代码。我建议你画个草图,想清楚看板要展示什么。
一个合格的监控看板,至少要有这四块:
- 实时数值展示:当前恐慌贪婪指数,带颜色编码
- 阈值告警:指数低于20或高于80时,自动弹窗/变色
- 历史走势图:过去7天、30天、90天的曲线
- 数据刷新机制:每5分钟自动拉取最新数据
嗯,这里要注意——别把看板做得太花哨。我曾经有个同事,把看板做成了赛博朋克风格,结果老板开会时盯着动画看了半天,完全没注意到指数已经跌到15了。简洁、清晰、一眼能看出问题,这才是王道。
3.2 数据源准备:从API获取恐慌贪婪指数
我们用的是Alternative.me的免费API。这个接口不需要API Key,直接GET就能拿到数据。
import requests
import pandas as pd
from datetime import datetime, timedelta
def fetch_fear_greed_index(days=30):
"""
获取恐慌贪婪指数历史数据
days: 过去多少天,最大支持365
"""
url = f"https://api.alternative.me/fng/?limit={days}&format=json"
try:
response = requests.get(url, timeout=10)
data = response.json()['data']
df = pd.DataFrame(data)
df['timestamp'] = pd.to_datetime(df['timestamp'], unit='s')
df['value'] = df['value'].astype(int)
df['value_classification'] = df['value_classification']
# 按时间排序
df = df.sort_values('timestamp')
return df
except Exception as e:
print(f"数据获取失败: {e}")
return None
# 测试一下
df = fetch_fear_greed_index(30)
print(df[['timestamp', 'value', 'value_classification']].tail())
这里有个坑——API返回的数据是按天更新的,不是实时秒级数据。所以别指望它能捕捉到分钟级别的波动。我个人习惯是每5分钟拉一次,如果数据没变就跳过,避免浪费请求。
3.3 Streamlit版本:10分钟搭一个可用看板
Streamlit是我最推荐的快速原型工具。你想想看,一个文件就能搞定前后端,多省事。
import streamlit as st
import plotly.graph_objects as go
from datetime import datetime
import time
# 页面配置
st.set_page_config(
page_title="恐慌贪婪指数监控看板",
page_icon="📊",
layout="wide"
)
st.title("📊 恐慌贪婪指数实时监控看板")
# 侧边栏配置
with st.sidebar:
st.header("⚙️ 设置")
refresh_interval = st.slider(
"刷新间隔(秒)",
min_value=60,
max_value=600,
value=300
)
# 阈值设置
st.subheader("🔔 告警阈值")
lower_threshold = st.slider(
"恐慌阈值(低于此值告警)",
0, 50, 20
)
upper_threshold = st.slider(
"贪婪阈值(高于此值告警)",
50, 100, 80
)
# 主区域
col1, col2, col3 = st.columns(3)
# 占位符,用于实时更新
placeholder_current = col1.empty()
placeholder_change = col2.empty()
placeholder_classification = col3.empty()
# 图表占位符
chart_placeholder = st.empty()
# 告警区域
alert_placeholder = st.empty()
# 主循环
while True:
# 获取最新数据
df = fetch_fear_greed_index(90)
if df is not None:
latest = df.iloc[-1]
current_value = latest['value']
classification = latest['value_classification']
# 更新当前值
with placeholder_current.container():
st.metric(
label="当前指数",
value=f"{current_value}/100",
delta=None
)
# 更新分类
with placeholder_classification.container():
color = "green" if current_value > 50 else "red"
st.markdown(
f"<h3 style='color:{color}'>{classification}</h3>"
)
# 阈值告警检查
if current_value <= lower_threshold:
alert_placeholder.error(
f"🚨 恐慌告警!指数 {current_value},低于阈值 {lower_threshold}"
)
elif current_value >= upper_threshold:
alert_placeholder.warning(
f"⚠️ 贪婪告警!指数 {current_value},高于阈值 {upper_threshold}"
)
else:
alert_placeholder.success("✅ 指数处于正常区间")
# 绘制历史走势图
fig = go.Figure()
fig.add_trace(go.Scatter(
x=df['timestamp'],
y=df['value'],
mode='lines+markers',
name='恐慌贪婪指数',
line=dict(color='#FF6B6B', width=2),
marker=dict(size=6)
))
# 添加阈值线
fig.add_hline(
y=lower_threshold,
line_dash="dash",
line_color="red",
annotation_text=f"恐慌阈值 {lower_threshold}"
)
fig.add_hline(
y=upper_threshold,
line_dash="dash",
line_color="green",
annotation_text=f"贪婪阈值 {upper_threshold}"
)
fig.update_layout(
title="恐慌贪婪指数历史走势(90天)",
xaxis_title="日期",
yaxis_title="指数值",
yaxis_range=[0, 100],
height=500,
template="plotly_white"
)
chart_placeholder.plotly_chart(fig, use_container_width=True)
# 等待指定时间后刷新
time.sleep(refresh_interval)
st.rerun()
💡 我的经验:Streamlit的rerun机制有个小问题——它会重新执行整个脚本。如果你的数据获取比较慢,建议用st.cache_data缓存历史数据,只刷新最新值。不然每次刷新都要等好几秒,体验很差。
3.4 Dash版本:更专业的实时看板
如果你需要部署到生产环境,或者需要更复杂的交互,我建议用Dash。它基于Flask,扩展性更强。
import dash
from dash import dcc, html, Input, Output
import plotly.graph_objects as go
import pandas as pd
import requests
from datetime import datetime
# 初始化Dash应用
app = dash.Dash(__name__)
app.layout = html.Div([
html.H1("恐慌贪婪指数实时监控看板",
style={'textAlign': 'center', 'color': '#2c3e50'}),
# 实时数值展示
html.Div([
html.Div([
html.H3("当前指数"),
html.H2(id='current-value', style={'color': '#e74c3c'})
], className='six columns'),
html.Div([
html.H3("市场情绪"),
html.H2(id='current-classification')
], className='six columns')
], style={'display': 'flex', 'justifyContent': 'space-around'}),
# 历史走势图
dcc.Graph(id='history-chart'),
# 告警区域
html.Div(id='alert-box', style={
'padding': '20px',
'margin': '20px 0',
'borderRadius': '5px'
}),
# 定时刷新组件
dcc.Interval(
id='interval-component',
interval=5*60*1000, # 5分钟
n_intervals=0
)
])
# 回调函数:更新数据
@app.callback(
[Output('current-value', 'children'),
Output('current-classification', 'children'),
Output('history-chart', 'figure'),
Output('alert-box', 'children'),
Output('alert-box', 'style')],
[Input('interval-component', 'n_intervals')]
)
def update_dashboard(n):
# 获取数据
df = fetch_fear_greed_index(90)
if df is None:
return "数据获取失败", "未知", go.Figure(), "请检查网络连接", {}
latest = df.iloc[-1]
current_value = latest['value']
classification = latest['value_classification']
# 绘制图表
fig = go.Figure()
fig.add_trace(go.Scatter(
x=df['timestamp'],
y=df['value'],
mode='lines+markers',
name='恐慌贪婪指数'
))
# 阈值线
fig.add_hline(y=20, line_dash="dash", line_color="red")
fig.add_hline(y=80, line_dash="dash", line_color="green")
fig.update_layout(
title="恐慌贪婪指数历史走势",
yaxis_range=[0, 100],
template="plotly_white"
)
# 告警逻辑
alert_style = {'padding': '20px', 'margin': '20px 0', 'borderRadius': '5px'}
if current_value <= 20:
alert_msg = f"🚨 极度恐慌!指数 {current_value}"
alert_style['backgroundColor'] = '#ffcccc'
alert_style['color'] = '#cc0000'
elif current_value >= 80:
alert_msg = f"⚠️ 极度贪婪!指数 {current_value}"
alert_style['backgroundColor'] = '#ccffcc'
alert_style['color'] = '#006600'
else:
alert_msg = f"✅ 市场情绪正常,指数 {current_value}"
alert_style['backgroundColor'] = '#e6f3ff'
alert_style['color'] = '#0066cc'
return (f"{current_value}/100", classification,
fig, alert_msg, alert_style)
if __name__ == '__main__':
app.run_server(debug=True, port=8050)
⚠️ 部署注意事项:
- Streamlit应用部署到Streamlit Cloud时,记得设置
secrets.toml管理敏感信息 - Dash应用建议用Gunicorn + Nginx部署,别直接用开发服务器
- 两个框架都支持Docker容器化,我推荐用Docker Compose统一管理
3.5 核心逻辑流程图
下面这张图,是我做这个看板时画的逻辑框架。你看一眼就能明白整个数据流是怎么跑的。
3.6 进阶功能:多指标联动监控
光看恐慌指数其实不够。我自己的实盘看板,还会同时监控这几个指标:
| 指标名称 | 数据来源 | 刷新频率 | 告警阈值 |
|---|---|---|---|
| 恐慌贪婪指数 | Alternative.me | 5分钟 | <20 或 >80 |
| BTC 价格 | Binance API | 实时 | 24h涨跌幅 >10% |
| 交易量 | CoinGecko | 1分钟 | 异常放量 >200% |
| 资金费率 | Bybit API | 8小时 | 绝对值 >0.1% |
把这些指标整合到一个看板上,你就能从多个维度判断市场状态。比如恐慌指数很低,但资金费率还是正的,说明市场可能还没到底——这时候抄底就要谨慎。
💡 我的实战技巧:别把所有告警都设成弹窗。我习惯把恐慌指数告警设成红色弹窗(紧急),把交易量异常设成黄色提示(关注),把资金费率变化记到日志里(参考)。分级告警能避免你被频繁打扰。
3.7 部署与运维建议
看板搭好了,怎么让它稳定跑起来?我踩过不少坑,给你几个建议:
- 使用进程管理工具:Supervisor或PM2,确保看板挂了能自动重启
- 加个健康检查接口:比如
/health返回200,配合UptimeRobot监控 - 数据持久化:把历史数据存到SQLite或PostgreSQL,避免每次重启都要重新拉
- 日志记录:记录每次告警触发的时间、指数值、操作建议,方便复盘
我曾经有一次,看板跑了两个月都没重启,结果API接口升级了,数据格式变了,看板直接崩了三天。从那以后,我每周都会手动检查一次看板状态,顺便看看日志里有没有异常。
好了,这一章的内容就到这里。你按照上面的代码,应该能在半小时内搭出一个能用的看板。记住,看板是工具,不是目的。真正重要的是——你看到告警后,敢不敢执行对应的交易策略。
公众号:蓝海资料掘金营,微信deep3321