AI炒股实测跑通!Qwen3/DeepSeek操盘ETF,数据自动爬,回测看收益

2025-11-25 17:49:39
文章摘要
硬核风险提示:本文为个人业余技术研究,所有ETF代码仅作示例,回测收益≠未来收益,绝不构成任何投资建议!股市有风险,入市需敬畏,决策靠自己。 不用付费数据源,不用啃复杂量化公式,用Qwen3/DeepSeek大模型就能搭ETF交易回测系统? 亲测可行!已整合免费金融数据接口,实现数据自动爬取、增量更新,大模型直接生成交易指令,回测基准对标沪深300。新手跟着抄作业,半小时就能搭起雏形。

先给结论:这个AI炒股项目能做什么?

别被“量化交易”吓住,这个项目的核心是“用AI简化决策”,目前已实现3大核心功能,普通人也能上手:

✅ 数据全自动

整合akshare免费接口,爬取中国市场ETF实时行情,支持增量更新(不用重复下历史数据)

✅ 大模型操盘

Qwen3/DeepSeek读取行情数据后生成交易指令,已实测Qwen3有完整交易记录

✅ 回测可视化

Web页面直接看收益曲线、持仓分析,回测基准锚定沪深300,收益一目了然

划重点:现在支持ETF,改个配置文件就能扩展到股票交易,后续加MACD、RSI指标也预留了接口。


实操环节:从0到1搭AI交易系统(附完整代码)

核心逻辑:数据采集→大模型分析→交易指令→回测可视化,全程Python实现,不用懂高深算法,跟着复制就行。

第一步:环境配置(5分钟搞定)

先装必备工具,新手直接复制命令到终端执行:

   

# 1. 安装核心库(akshare是免费金融数据神器)
pip install akshare python-dotenv pandas json

# 2. 新建.env文件(存敏感信息,避免硬编码)
# 格式:HF_TOKEN=你的HuggingFace密钥(大模型调用用)

   akshare优势:比Wind、Tushare免费,中国市场数据超全(ETF/股票/基金都能爬),接口稳定,个人研究够用了。


第二步:核心代码拆解(关键部分附通俗解释)

代码分4个核心模块,每个模块都加了新手能懂的注释,直接复制到main.py即可。

模块1:初始化与ETF池配置

先定义要监控的ETF,选的都是跨境+资源类,分散风险,新手直接用这个组合就行:

import os
from dotenv import load_dotenv
load_dotenv()  # 加载.env里的密钥,安全!
import json
import akshare as ak
from datetime import datetime, timedelta

# 核心:要交易的ETF池(附注释,清楚每只的作用)
all_zh_symbols = [
    # 海外市场(分散单一市场风险)
    "159561"# 嘉实德国DAX ETF(欧洲市场)
    "513880"# 日经225ETF(日本市场)
    "513500"# 标普500ETF(美国市场)
    # 香港市场(中概核心资产)
    "513130",  # 恒生科技ETF(腾讯/阿里等)
    "513830",  # 港股红利ETF(高股息防御)
    # 资源类(抗通胀)
    "160416",  # 华安标普全球石油指数LOF
    "518880",  # 黄金ETF(避险神器)
]


为什么选ETF不选个股?ETF费率低、分散风险,就算单只股票跌,对整体影响小,特别适合新手练手。


模块2:代码格式转换(对接akshare的关键)

akshare需要区分上海/深圳交易所,这个函数自动加前缀,不用手动改:

def add_sh_sz(symbol):
    """给股票代码加交易所前缀(sh=上海,sz=深圳)"""
    if symbol.startswith(("6","5")):  # 6/5开头是上海股
        symbol = f"sh{symbol}"
    elif symbol.startswith(("0","1","3")):  # 0/1/3开头是深圳股
        symbol = f"sz{symbol}"
    return symbol

# 示例:输入513500→输出sh513500(标普500ETF在上海上市)
print(add_sh_sz("513500"))


   模块3:数据增量更新(省时间省流量)

核心亮点:不会重复下历史数据,只更最新的,爬取效率翻倍。分两个函数实现

def get_last_refreshed_date(SYMBOL: str):
    """查本地数据的最后更新时间,避免重复爬取"""
    filename = f'./daily_prices_{SYMBOL}.json'
    if os.path.exists(filename):
        try:
            with open(filename, 'r', encoding='utf-8'as f:
                data = json.load(f)
                # 从数据里提取最后更新日期
                last_date = data.get("Meta Data", {}).get("3. Last Refreshed")
                if last_date:
                    return datetime.strptime(last_date, "%Y-%m-%d")
        except Exception as e:
            print(f"文件读取错了:{e}")
    return None  # 没本地数据就返回空

def get_daily_price(SYMBOL: str):
    """核心:爬取ETF日线数据,支持增量更新"""
    last_date = get_last_refreshed_date(SYMBOL)
    
    # 确定爬取时间范围:有历史数据就从次日开始,没有就从2025年11月1日开始
    if last_date:
        start_date = (last_date + timedelta(days=1)).strftime("%Y%m%d")
        print(f"上次更到{last_date.strftime('%Y-%m-%d')},从{start_date}开始更")
    else:
        start_date = "20251101"
        print(f"没历史数据,从{start_date}开始爬")
    
    end_date = datetime.now().strftime("%Y%m%d")
    print(f"爬取时间:{start_date} 到 {end_date}")

    # 调用akshare爬数据(自动加交易所前缀)
    df = ak.fund_etf_hist_sina(symbol=add_sh_sz(SYMBOL))
    print(f"爬到{df.shape[0]}条数据,包含开盘价/最高价/收盘价/成交量")
    
    if df.empty:
        print("没爬到新数据")
        return
    
    # 数据处理:合并历史数据+保存
    filename = f'./daily_prices_{SYMBOL}.json'
    if last_date:  # 有历史数据就合并
        with open(filename, 'r', encoding='utf-8'as f:
            old_data = json.load(f)
        # 新数据转成字典格式
        new_data = {}
        for _, row in df.iterrows():
            date_str = str(row['date'])
            new_data[date_str] = {
                "1. open"str(row['open']),
                "2. high"str(row['high']),
                "3. low"str(row['low']),
                "4. close"str(row['close']),
                "5. volume"str(row['volume'])
            }
        # 合并新旧数据,新数据覆盖旧数据
        old_data["Time Series (Daily)"].update(new_data)
        old_data["Meta Data"]["3. Last Refreshed"] = end_date
        final_data = old_data
    else:  # 没历史数据就新建格式
        final_data = {
            "Meta Data": {
                "1. 说明""ETF日线数据(开盘/最高/最低/收盘/成交量)",
                "2. 代码": SYMBOL,
                "3. Last Refreshed": end_date,
                "4. 时区""Asia/Shanghai"
            },
            "Time Series (Daily)": {}
        }
        # 填充新数据
        for _, row in df.iterrows():
            date_str = str(row['date'])
            final_data["Time Series (Daily)"][date_str] = {
                "1. open"str(row['open']),
                "2. high"str(row['high']),
                "3. low"str(row['low']),
                "4. close"str(row['close']),
                "5. volume"str(row['volume'])
            }
    
    # 保存到本地JSON文件
    with open(filename, 'w', encoding='utf-8'as f:
        json.dump(final_data, f, ensure_ascii=False, indent=4)
    print(f"数据存好了:{filename}")



   模块4:调用大模型生成交易指令

核心逻辑:把爬好的数据喂给Qwen3/DeepSeek,让模型根据行情给交易建议(买/卖/持仓):



def get_llm_trade_signal(SYMBOL: str):
    """用大模型分析数据,生成交易指令"""
    # 读取本地数据
    filename = f'./daily_prices_{SYMBOL}.json'
    if not os.path.exists(filename):
        print(f"没找到{SYMBOL}的数据,先爬数据!")
        return
    
    with open(filename, 'r', encoding='utf-8') as f:
        data = json.load(f)
    # 取最近10天的行情(给模型的上下文不用太多)
    recent_dates = sorted(data["Time Series (Daily)"].keys())[-10:]
    recent_data = {date: data["Time Series (Daily)"][date] for date in recent_dates}
    
    # 构造提示词(关键:明确告诉模型要做什么)
    prompt = f"""
    你是专业ETF交易分析师,基于以下{SYMBOL}的最近10天行情数据,结合沪深300基准,给出交易建议:
    数据:{recent_data}
    要求:1. 输出"买入"/"卖出"/"持仓观望";2. 简单说明理由(不超过50字);3. 不用专业术语。
    """
    
    # 调用Qwen3(这里用伪代码,实际需对接大模型API)
    # 实际部署可参考通义千问/DeepSeek的官方SDK
    from openai import OpenAI # 示例,需替换为对应大模型的SDK
    client = OpenAI(base_url="你的大模型地址", api_key=os.getenv("LLM_API_KEY"))
    response = client.chat.completions.create(
        model="qwen3",
        messages=[{"role": "user", "content": prompt}]
    )
    signal = response.choices[0].message.content
    print(f"\n{SYMBOL}的交易建议:{signal}")
    return signal

# 主函数:遍历所有ETF,爬数据+要交易指令
if __name__ == "__main__":
    for symbol in all_zh_symbols:
        print(f"\n===== 处理ETF:{symbol} =====")
        get_daily_price(symbol)  # 爬数据
        get_llm_trade_signal(symbol)  # 要交易指令




实测效果:大模型真的会“炒股”吗?

跑起程序后,两个大模型的表现很有意思,直接上结果:

1. 交易指令差异明显

 Qwen3:反应灵活,有明确交易记录。比如看到黄金ETF连续3天上涨,给出“持仓观望,短期涨幅大需警惕回调”;标普500ETF下跌2%时,建议“小仓位买入,分散风险”。

 DeepSeek:偏保守,全程持仓不动。理由是“当前ETF波动在合理范围,无明确买卖信号,避免频繁交易”。

👉 后续计划:拉长回测时间到3个月,增加5只A股ETF,看DeepSeek是否会触发交易信号。


2. Web可视化看收益(新手也能懂)

运行Web服务就能看直观的收益曲线,步骤超简单:

# 进入文档目录,启动本地服务
cd docs
python -m http.server 8000


打开http://localhost:8000,就能看到:

 📈 收益曲线:Qwen3的模拟收益 vs 沪深300基准,涨跌幅一目了然;

 📊 持仓分析:每只ETF的持仓占比、买入时间、浮盈浮亏;

 💬 对话记录:大模型给出交易建议的完整逻辑,方便复盘。

(附实测截图:Qwen3模拟收益跑赢沪深300约1.2%,当然这只是短期回测,不代表真实收益)


未来升级计划:从ETF到股票,从日线到分钟线

这个项目只是雏形,后续这3个方向会重点升级,代码已预留接口:

1.  支持股票交易:把all_zh_symbols换成股票代码(比如贵州茅台600519),提前爬取股票数据即可,逻辑完全复用。

2.  加技术指标:引入MACD、RSI、布林带等,给大模型更丰富的分析依据。比如当RSI>70时,模型会自动识别“超买信号”。

3.  多周期数据:现在是日线,后续加分钟线(适合短线)、周线(适合长线),满足不同交易风格。


最后:为什么普通人要学AI+金融?

不是说要靠AI炒股赚钱,而是在AGI时代,“AI+专业领域”的能力已经成了职场护城河:

我身边做金融的同事,用AI自动爬取研报、生成分析报告,效率比以前高3倍;做量化的朋友,用大模型优化交易策略,省去了大量调参时间。

这个炒股项目,本质是帮你练手“大模型+数据处理+行业落地”的完整能力——就算不做金融,这套逻辑套到电商、教育等领域也同样适用。




声明:该内容由作者自行发布,观点内容仅供参考,不代表平台立场;如有侵权,请联系平台删除。