第三章:指数实时监控看板

说实话,做量化交易这么多年,我最大的体会就是——数据看板不是用来好看的,是用来救命的

记得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 核心逻辑流程图

下面这张图,是我做这个看板时画的逻辑框架。你看一眼就能明白整个数据流是怎么跑的。

恐慌贪婪指数监控看板 - 数据流架构 Alternative.me API 恐慌贪婪指数数据 数据处理层 数据清洗 → 格式转换 → 缓存管理 阈值告警引擎 恐慌阈值 <= 20 贪婪阈值 >= 80 可视化引擎 Plotly 图表绘制 实时数值展示 告警输出 弹窗 / 邮件 / 钉钉 看板展示 Streamlit / Dash 数据刷新间隔:5分钟 | 支持自定义阈值 | 历史数据回溯90天

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