Skip to content

每日股票分析

每日股票分析 #42

name: 每日股票分析
on:
# 定时触发 - 每天北京时间 18:00 (UTC 10:00)
schedule:
- cron: '0 10 * * 1-5' # 周一到周五,UTC 10:00 = 北京时间 18:00
# 手动触发
workflow_dispatch:
inputs:
mode:
description: '运行模式'
required: true
default: 'full'
type: choice
options:
- full # 完整分析(股票+大盘)
- market-only # 仅大盘复盘
- stocks-only # 仅股票分析
force_run:
description: '强制运行(跳过交易日检查)'
required: false
default: false
type: boolean
# 并发控制:同一时间只运行一个分析任务
concurrency:
group: stock-analysis
cancel-in-progress: false
jobs:
analyze:
runs-on: ubuntu-latest
# 添加超时限制,防止任务卡死
timeout-minutes: 30
steps:
- name: 随机延迟(避免固定时间访问)
run: sleep $((RANDOM % 60)) # 随机延迟0-60秒启动
- name: 检出代码
uses: actions/checkout@v5
- name: 设置 Python 环境
uses: actions/setup-python@v6
with:
python-version: '3.11'
cache: 'pip'
- name: 安装依赖
run: |
pip install --upgrade pip
pip install -r requirements.txt
- name: 创建必要目录
run: |
mkdir -p data logs reports
- name: 执行股票分析
env:
# ==========================================
# AI 配置
# ==========================================
# LITELLM_CONFIG
LITELLM_CONFIG: ${{ vars.LITELLM_CONFIG || secrets.LITELLM_CONFIG }}
LITELLM_CONFIG_YAML: ${{ vars.LITELLM_CONFIG_YAML || secrets.LITELLM_CONFIG_YAML }}
LITELLM_API_KEY: ${{ secrets.LITELLM_API_KEY }}
LITELLM_MODEL: ${{ vars.LITELLM_MODEL || secrets.LITELLM_MODEL }}
# Gemini AI(主选)
GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
GEMINI_MODEL: ${{ vars.GEMINI_MODEL || secrets.GEMINI_MODEL || 'gemini-3-flash-preview' }}
GEMINI_MODEL_FALLBACK: ${{ vars.GEMINI_MODEL_FALLBACK || secrets.GEMINI_MODEL_FALLBACK || 'gemini-2.5-flash' }}
GEMINI_REQUEST_DELAY: '3.0'
# AIHubMix(优先于 OPENAI_API_KEY,自动适配 base_url,推荐国内用户)
AIHUBMIX_KEY: ${{ secrets.AIHUBMIX_KEY }}
# OpenAI 兼容 API(备选)
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
OPENAI_BASE_URL: ${{ vars.OPENAI_BASE_URL || secrets.OPENAI_BASE_URL }}
OPENAI_MODEL: ${{ vars.OPENAI_MODEL || secrets.OPENAI_MODEL }}
# Anthropic / Claude
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
ANTHROPIC_MODEL: ${{ vars.ANTHROPIC_MODEL || secrets.ANTHROPIC_MODEL || 'claude-3-5-sonnet-20241022' }}
# ==========================================
# 数据源
# ==========================================
TUSHARE_TOKEN: ${{ secrets.TUSHARE_TOKEN }}
# ==========================================
# 搜索服务
# ==========================================
BOCHA_API_KEYS: ${{ secrets.BOCHA_API_KEYS }}
TAVILY_API_KEYS: ${{ secrets.TAVILY_API_KEYS }}
SERPAPI_API_KEYS: ${{ secrets.SERPAPI_API_KEYS }}
MINIMAX_API_KEYS: ${{ secrets.MINIMAX_API_KEYS }}
BRAVE_API_KEYS: ${{ secrets.BRAVE_API_KEYS }}
SEARXNG_BASE_URLS: ${{ secrets.SEARXNG_BASE_URLS }}
# ==========================================
# 通知渠道(可同时配置多个,全部推送)
# ==========================================
# 方式一:企业微信 Webhook
WECHAT_WEBHOOK_URL: ${{ secrets.WECHAT_WEBHOOK_URL }}
WECHAT_MSG_TYPE: ${{ vars.WECHAT_MSG_TYPE || secrets.WECHAT_MSG_TYPE || 'markdown' }}
# 方式二:飞书 Webhook
FEISHU_WEBHOOK_URL: ${{ secrets.FEISHU_WEBHOOK_URL }}
# 方式三:Telegram
TELEGRAM_BOT_TOKEN: ${{ secrets.TELEGRAM_BOT_TOKEN }}
TELEGRAM_CHAT_ID: ${{ secrets.TELEGRAM_CHAT_ID }}
TELEGRAM_MESSAGE_THREAD_ID: ${{ secrets.TELEGRAM_MESSAGE_THREAD_ID }}
# 方式四:邮件
EMAIL_SENDER: ${{ vars.EMAIL_SENDER || secrets.EMAIL_SENDER }}
EMAIL_PASSWORD: ${{ secrets.EMAIL_PASSWORD }}
EMAIL_RECEIVERS: ${{ vars.EMAIL_RECEIVERS || secrets.EMAIL_RECEIVERS }}
EMAIL_SENDER_NAME: ${{ vars.EMAIL_SENDER_NAME || secrets.EMAIL_SENDER_NAME || 'daily_stock_analysis股票分析助手' }}
# 方式五:Pushover
PUSHOVER_USER_KEY: ${{ secrets.PUSHOVER_USER_KEY }}
PUSHOVER_API_TOKEN: ${{ secrets.PUSHOVER_API_TOKEN }}
# 方式六:PushPlus ⬅️ 新增!
PUSHPLUS_TOKEN: ${{ secrets.PUSHPLUS_TOKEN }}
# 方式七:自定义 Webhook(钉钉、Bark、自建服务等)
CUSTOM_WEBHOOK_URLS: ${{ secrets.CUSTOM_WEBHOOK_URLS }}
CUSTOM_WEBHOOK_BEARER_TOKEN: ${{ secrets.CUSTOM_WEBHOOK_BEARER_TOKEN }}
# 方式八:Discord
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
DISCORD_BOT_TOKEN: ${{ secrets.DISCORD_BOT_TOKEN }}
DISCORD_MAIN_CHANNEL_ID: ${{ secrets.DISCORD_MAIN_CHANNEL_ID }}
# 方式九:飞书云文档
FEISHU_APP_ID: ${{ secrets.FEISHU_APP_ID }}
FEISHU_APP_SECRET: ${{ secrets.FEISHU_APP_SECRET }}
FEISHU_FOLDER_TOKEN: ${{ secrets.FEISHU_FOLDER_TOKEN }}
# 方式十:AstrBot
ASTRBOT_URL: ${{ secrets.ASTRBOT_URL }}
ASTRBOT_TOKEN: ${{ secrets.ASTRBOT_TOKEN }}
# 方式十一:Server酱3
SERVERCHAN3_SENDKEY: ${{ secrets.SERVERCHAN3_SENDKEY }}
# ==========================================
# 自选股配置
# ==========================================
STOCK_LIST: ${{ vars.STOCK_LIST || secrets.STOCK_LIST || '600519' }}
MARKET_REVIEW_REGION: ${{ vars.MARKET_REVIEW_REGION || secrets.MARKET_REVIEW_REGION || 'cn' }}
# ==========================================
# 运行配置 ⬅️ 新增!
# ==========================================
REPORT_TYPE: ${{ vars.REPORT_TYPE || secrets.REPORT_TYPE || 'simple' }}
SINGLE_STOCK_NOTIFY: ${{ vars.SINGLE_STOCK_NOTIFY || secrets.SINGLE_STOCK_NOTIFY || 'false' }}
MARKET_REVIEW_ENABLED: ${{ vars.MARKET_REVIEW_ENABLED || secrets.MARKET_REVIEW_ENABLED || 'true' }}
ANALYSIS_DELAY: ${{ vars.ANALYSIS_DELAY || secrets.ANALYSIS_DELAY || '0' }}
TRADING_DAY_CHECK_ENABLED: ${{ vars.TRADING_DAY_CHECK_ENABLED || secrets.TRADING_DAY_CHECK_ENABLED || 'true' }}
# ==========================================
# 系统配置
# ==========================================
LOG_LEVEL: INFO
MAX_WORKERS: ${{ vars.MAX_WORKERS || secrets.MAX_WORKERS || '1' }}
# 筹码分布:默认 false(云端接口不稳定);需启用时在 Settings → Variables 添加 ENABLE_CHIP_DISTRIBUTION=true
ENABLE_CHIP_DISTRIBUTION: ${{ vars.ENABLE_CHIP_DISTRIBUTION || secrets.ENABLE_CHIP_DISTRIBUTION || 'false' }}
# 实时行情数据源优先级(腾讯有量比且稳定,推荐首选)
# 可选值: tencent, akshare_sina, efinance, akshare_em, tushare
# 如果有 Tushare Pro 高积分账号,可将 tushare 放在首位
REALTIME_SOURCE_PRIORITY: ${{ vars.REALTIME_SOURCE_PRIORITY || 'tencent,akshare_sina,efinance,akshare_em' }}
run: |
# 处理 LITELLM YAML 配置文件
if [ -n "$LITELLM_CONFIG_YAML" ] && [ -n "$LITELLM_CONFIG" ]; then
echo "📝 使用 GitHub Actions Secrets/Variables 中的 LITELLM_CONFIG_YAML 配置"
# 确保目录存在
mkdir -p "$(dirname "$LITELLM_CONFIG")"
# 写入配置文件(覆盖已有文件)
echo "$LITELLM_CONFIG_YAML" > "$LITELLM_CONFIG"
echo "✅ LITELLM 配置文件已写入: $LITELLM_CONFIG"
fi
# 判断运行模式
MODE="${{ github.event.inputs.mode || 'full' }}"
echo "=========================================="
echo "🚀 A股自选股智能分析系统"
echo "=========================================="
echo "⏰ 时间: $(TZ='Asia/Shanghai' date '+%Y-%m-%d %H:%M:%S')"
echo "🎯 运行模式: $MODE"
echo "📊 自选股: $STOCK_LIST"
echo "📝 报告类型: $REPORT_TYPE"
echo ""
echo "=========================================="
echo "📋 配置检查"
echo "=========================================="
echo "【AI 配置】"
echo " LiteLLM: $([ -n "$LITELLM_CONFIG" ] || [ -n "$LITELLM_API_KEY" ] || [ -n "$LITELLM_MODEL" ] && echo '✅ 已配置' || echo '❌ 未配置')"
echo " Gemini API Key: $([ -n "$GEMINI_API_KEY" ] && echo '✅ 已配置' || echo '❌ 未配置')"
echo " AIHubMix Key: $([ -n "$AIHUBMIX_KEY" ] && echo '✅ 已配置' || echo '⚪ 未配置')"
echo " OpenAI API Key: $([ -n "$OPENAI_API_KEY" ] && echo '✅ 已配置' || echo '⚪ 未配置')"
echo " Anthropic Key: $([ -n "$ANTHROPIC_API_KEY" ] && echo '✅ 已配置' || echo '⚪ 未配置')"
echo ""
echo "【搜索引擎】"
echo " Bocha API Keys: $([ -n "$BOCHA_API_KEYS" ] && echo '✅ 已配置' || echo '⚪ 未配置')"
echo " Tavily API Keys: $([ -n "$TAVILY_API_KEYS" ] && echo '✅ 已配置' || echo '⚪ 未配置')"
echo " SerpAPI Keys: $([ -n "$SERPAPI_API_KEYS" ] && echo '✅ 已配置' || echo '⚪ 未配置')"
echo " MiniMax API Keys: $([ -n "$MINIMAX_API_KEYS" ] && echo '✅ 已配置' || echo '⚪ 未配置')"
echo " Brave API Keys: $([ -n "$BRAVE_API_KEYS" ] && echo '✅ 已配置' || echo '⚪ 未配置')"
echo " SearXNG Base URLs: $([ -n "$SEARXNG_BASE_URLS" ] && echo '✅ 已配置' || echo '⚪ 未配置')"
echo ""
echo "【通知渠道】"
echo " PushPlus: $([ -n "$PUSHPLUS_TOKEN" ] && echo '✅ 已配置' || echo '⚪ 未配置')"
echo " 企业微信: $([ -n "$WECHAT_WEBHOOK_URL" ] && echo '✅ 已配置' || echo '⚪ 未配置')"
echo " 飞书: $([ -n "$FEISHU_WEBHOOK_URL" ] && echo '✅ 已配置' || echo '⚪ 未配置')"
echo " Telegram: $([ -n "$TELEGRAM_BOT_TOKEN" ] && echo '✅ 已配置' || echo '⚪ 未配置')"
echo " Discord: $([ -n "$DISCORD_WEBHOOK_URL" ] && echo '✅ 已配置' || echo '⚪ 未配置')"
echo " AstrBot: $([ -n "$ASTRBOT_URL" ] && echo '✅ 已配置' || echo '⚪ 未配置')"
echo "=========================================="
echo ""
# 构建命令行参数
FORCE_RUN_ARG=""
if [ "${{ github.event.inputs.force_run }}" = "true" ]; then
FORCE_RUN_ARG="--force-run"
echo "⚡ 已启用强制运行模式(跳过交易日检查)"
fi
# 执行分析
if [ "$MODE" = "market-only" ]; then
python main.py --market-review $FORCE_RUN_ARG
elif [ "$MODE" = "stocks-only" ]; then
python main.py --no-market-review $FORCE_RUN_ARG
else
python main.py $FORCE_RUN_ARG
fi
- name: 上传分析报告
uses: actions/upload-artifact@v6
if: always()
with:
name: analysis-reports-${{ github.run_number }}
path: |
reports/
logs/
retention-days: 30
- name: 显示运行结果
if: always()
run: |
echo ""
echo "=========================================="
echo "📊 分析完成"
echo "=========================================="
if [ -d "reports" ] && [ "$(ls -A reports 2>/dev/null)" ]; then
echo "生成的报告:"
ls -la reports/
else
echo "⚠️ 未生成报告文件"
fi
echo ""
if [ -f "logs/stock_analysis_$(date +%Y%m%d).log" ]; then
echo "📜 最近日志(最后 30 行):"
tail -30 logs/stock_analysis_*.log 2>/dev/null || echo "无日志"
fi