From a3b16ffa8da36cf6a9d87166288cb4d2f3149195 Mon Sep 17 00:00:00 2001 From: sam Date: Sat, 27 Sep 2025 16:26:03 +0800 Subject: [PATCH] update --- README.md | 36 ++++++++++++++++++++++- app/ui/streamlit_app.py | 65 ++++++++++++++++++++++++++++++++++++++--- requirements.txt | 4 +++ 3 files changed, 100 insertions(+), 5 deletions(-) create mode 100644 requirements.txt diff --git a/README.md b/README.md index f1a08ec..cf028bc 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,10 @@ # 多智能体投资助理骨架 -本仓库提供一个基于多智能体博弈的 A 股日线投资助理代码框架,满足单机可运行、SQLite 存储和 Streamlit UI 的需求。核心模块划分如下: +## 项目简介 + +本仓库提供一个面向 A 股日线级别的多智能体投资助理原型,覆盖数据采集、特征抽取、策略博弈、回测展示和 LLM 解释链路。代码以模块化骨架形式呈现,方便在单机环境下快速搭建端到端的量化研究和可视化决策流程。 + +## 核心模块 - `app/data`:数据库初始化与 Schema 定义。 - `app/utils`:配置、数据库连接、日志和交易日历工具。 @@ -11,6 +15,36 @@ - `app/llm`:人类可读卡片与摘要生成入口(仅构建提示,不直接交易)。 - `app/ui`:Streamlit 四页界面骨架,含“自检测试”页。 +## 核心技术原理 + +- **多智能体博弈**:通过 `app/agents` 定义六类风格化代理,利用纳什谈判与加权投票在 `app/agents/game.py` 中聚合交易动作与信心水平。 +- **数据覆盖自检**:`app/ingest/tushare.py` 封装 TuShare 拉取、增量更新与覆盖统计,`app/ingest/checker.py` 提供强制补数与窗口化覆盖报告。 +- **事件驱动回测**:`app/backtest/engine.py` 构建日频回测循环,将代理决策与投资组合状态解耦,便于扩展成交撮合与绩效统计。 +- **可视化与解释**:`app/ui/streamlit_app.py` 提供四大页签(今日计划、回测与复盘、数据与设置、自检测试),结合 Plotly 图形展示和 `app/llm` 提示卡片生成器,支撑人机协作分析。 + +## 环境依赖与安装 + +建议使用 Python 3.10+,并在虚拟环境中安装依赖。 + +```bash +# 1. 创建并激活虚拟环境(示例使用 venv) +python -m venv .venv +source .venv/bin/activate # Windows 使用 .venv\Scripts\activate + +# 2. 安装项目依赖 +pip install -r requirements.txt + +# 3. 设置 TuShare Token(可写入环境变量或在 UI 中配置) +export TUSHARE_TOKEN="" +``` + +`requirements.txt` 当前涵盖运行框架所需的核心三方库: + +- Pandas:数据表结构与指标处理 +- Streamlit:交互式前端 +- Plotly:行情与指标可视化 +- TuShare:行情与基础面数据源 + ## 快速开始 ```bash diff --git a/app/ui/streamlit_app.py b/app/ui/streamlit_app.py index 99b127a..0a9e1ed 100644 --- a/app/ui/streamlit_app.py +++ b/app/ui/streamlit_app.py @@ -10,6 +10,8 @@ if str(ROOT) not in sys.path: sys.path.insert(0, str(ROOT)) import pandas as pd +import plotly.express as px +import plotly.graph_objects as go import streamlit as st from app.backtest.engine import BtConfig, run_backtest @@ -248,10 +250,65 @@ def render_tests() -> None: metric_col2.metric("区间涨跌幅", f"{delta_pct:+.2f}%") metric_col3.metric("平均成交量", f"{volume_sampled['成交量(手)'].mean():.0f}") - st.line_chart(sampled, width='stretch') - st.bar_chart(volume_sampled, width='stretch') - st.caption("提示:成交量单位为手,若需更长区间请调整日期后重新加载。") - st.dataframe(df.reset_index().tail(10), width='stretch') + df_reset = df.reset_index().rename(columns={ + "trade_date": "交易日", + "open": "开盘价", + "high": "最高价", + "low": "最低价", + "close": "收盘价", + "vol": "成交量(手)", + "amount": "成交额(千元)", + }) + df_reset["成交额(千元)"] = df_reset["成交额(千元)"] / 1000 + + candle_fig = go.Figure( + data=[ + go.Candlestick( + x=df_reset["交易日"], + open=df_reset["开盘价"], + high=df_reset["最高价"], + low=df_reset["最低价"], + close=df_reset["收盘价"], + name="K线", + ) + ] + ) + candle_fig.update_layout(height=420, margin=dict(l=10, r=10, t=40, b=10)) + st.plotly_chart(candle_fig, use_container_width=True) + + vol_fig = px.bar( + df_reset, + x="交易日", + y="成交量(手)", + labels={"成交量(手)": "成交量(手)"}, + title="成交量", + ) + vol_fig.update_layout(height=280, margin=dict(l=10, r=10, t=40, b=10)) + st.plotly_chart(vol_fig, use_container_width=True) + + amt_fig = px.bar( + df_reset, + x="交易日", + y="成交额(千元)", + labels={"成交额(千元)": "成交额(千元)"}, + title="成交额", + ) + amt_fig.update_layout(height=280, margin=dict(l=10, r=10, t=40, b=10)) + st.plotly_chart(amt_fig, use_container_width=True) + + df_reset["月份"] = df_reset["交易日"].dt.to_period("M").astype(str) + box_fig = px.box( + df_reset, + x="月份", + y="收盘价", + points="outliers", + title="月度收盘价分布", + ) + box_fig.update_layout(height=320, margin=dict(l=10, r=10, t=40, b=10)) + st.plotly_chart(box_fig, use_container_width=True) + + st.caption("提示:成交量单位为手,成交额以千元显示。箱线图按月展示收盘价分布。") + st.dataframe(df_reset.tail(20), width='stretch') def main() -> None: diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..ac1912c --- /dev/null +++ b/requirements.txt @@ -0,0 +1,4 @@ +pandas>=2.0 +plotly>=5.18 +streamlit>=1.30 +tushare>=1.2