news 2026/7/29 15:50:56

python:backtrader 如何使用 tushare 股票数据?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
python:backtrader 如何使用 tushare 股票数据?

我来详细介绍在Backtrader中使用Tushare数据的几种方法,从简单到复杂,包括示例代码。

方法1:使用PandasData(推荐,最灵活)

这是最常用的方法,将Tushare数据转换为Pandas DataFrame,然后用Backtrader的PandasData适配器加载。

基本示例

importbacktraderasbtimporttushareastsimportpandasaspdfromdatetimeimportdatetime# 1. 从Tushare获取数据defget_tushare_data(ts_code='000001.SZ',start_date='20200101',end_date='20231231'):""" 获取Tushare股票数据并转换为Backtrader需要的格式 """# 初始化tushare(需要token)ts.set_token('你的tushare_token')# 替换为你的tokenpro=ts.pro_api()# 获取日线数据df=pro.daily(ts_code=ts_code,start_date=start_date,end_date=end_date)# 数据清洗和格式化df=df.sort_values('trade_date')# 按日期排序df['trade_date']=pd.to_datetime(df['trade_date'])# 转换为datetimedf.set_index('trade_date',inplace=True)# 设置日期为索引# 重命名列以匹配Backtrader的PandasDatadf.rename(columns={'open':'Open','high':'High','low':'Low','close':'Close','vol':'Volume'},inplace=True)# 只保留需要的列df=df[['Open','High','Low','Close','Volume']]returndf# 2. 创建自定义的PandasData类(可选,处理Tushare特有字段)classTusharePandasData(bt.feeds.PandasData):""" 自定义PandasData以处理Tushare数据 可以添加更多字段如换手率、涨跌幅等 """params=(('datetime',None),# 使用索引作为datetime('open','Open'),('high','High'),('low','Low'),('close','Close'),('volume','Volume'),('openinterest',-1),# 无持仓量字段# 可以添加额外字段# ('pct_chg', 'pct_chg'), # 如果需要涨跌幅)# 3. 完整的回测示例classSmaCrossStrategy(bt.Strategy):params=(('fast',10),('slow',30),)def__init__(self):self.fast_sma=bt.indicators.SMA(self.data.close,period=self.params.fast)self.slow_sma=bt.indicators.SMA(self.data.close,period=self.params.slow)self.crossover=bt.indicators.CrossOver(self.fast_sma,self.slow_sma)defnext(self):ifnotself.position:ifself.crossover>0:# 金叉self.buy()elifself.crossover<0:# 死叉self.close()defrun_backtest():# 创建Cerebro引擎cerebro=bt.Cerebro()# 获取数据print("正在获取数据...")df=get_tushare_data('000001.SZ','20200101','20231231')ifdf.empty:print("数据获取失败,请检查网络或token")returnprint(f"数据量:{len(df)}条")print(f"日期范围:{df.index[0]}{df.index[-1]}")# 创建数据源data=TusharePandasData(dataname=df)# 添加到引擎cerebro.adddata(data)# 添加策略cerebro.addstrategy(SmaCrossStrategy)# 设置初始资金cerebro.broker.setcash(100000.0)# 设置佣金cerebro.broker.setcommission(commission=0.001)# 0.1%佣金# 添加分析器cerebro.addanalyzer(bt.analyzers.Returns,_name='returns')cerebro.addanalyzer(bt.analyzers.SharpeRatio,_name='sharpe')cerebro.addanalyzer(bt.analyzers.DrawDown,_name='drawdown')cerebro.addanalyzer(bt.analyzers.TradeAnalyzer,_name='trades')# 运行回测print('初始资金: %.2f'%cerebro.broker.getvalue())results=cerebro.run()print('最终资金: %.2f'%cerebro.broker.getvalue())# 打印分析结果strat=results[0]print("\n=== 策略绩效 ===")print(f"总收益率:{strat.analyzers.returns.get_analysis()['rtot']:.2%}")sharpe_ratio=strat.analyzers.sharpe.get_analysis()print(f"夏普比率:{sharpe_ratio['sharperatio']:.3f}")drawdown=strat.analyzers.drawdown.get_analysis()print(f"最大回撤:{drawdown['max']['drawdown']:.2%}")print(f"最长回撤周期:{drawdown['max']['len']}天")trades=strat.analyzers.trades.get_analysis()if'total'intrades:print(f"总交易次数:{trades['total']['total']}")print(f"盈利交易:{trades['won']['total']}")print(f"亏损交易:{trades['lost']['total']}")iftrades['won']['total']>0:print(f"胜率:{trades['won']['total']/trades['total']['total']:.2%}")# 绘制图表cerebro.plot(style='candlestick',volume=True)if__name__=='__main__':run_backtest()

方法2:使用通用CSVData(保存为CSV再读取)

如果不想每次都从Tushare API获取,可以先保存到本地CSV。

importbacktraderasbtimporttushareastsimportpandasaspdimportosclassTushareCSVData(bt.feeds.GenericCSVData):""" 自定义CSV数据加载器 """params=(('datetime',0),# 日期列索引('open',1),# 开盘价列索引('high',2),# 最高价列索引('low',3),# 最低价列索引('close',4),# 收盘价列索引('volume',5),# 成交量列索引('openinterest',-1),# 无持仓量('dtformat','%Y-%m-%d'),# 日期格式('nullvalue',0.0),)defdownload_and_save_tushare_data(ts_code='000001.SZ',start_date='20200101',end_date='20231231',save_path='data.csv'):"""下载Tushare数据并保存为CSV"""ts.set_token('你的tushare_token')pro=ts.pro_api()df=pro.daily(ts_code=ts_code,start_date=start_date,end_date=end_date)# 格式化df=df.sort_values('trade_date')df['trade_date']=pd.to_datetime(df['trade_date'])# 保存为CSVdf.to_csv(save_path,index=False)print(f"数据已保存到:{save_path}")returnsave_path# 使用示例csv_file=download_and_save_tushare_data('000001.SZ')data=TushareCSVData(dataname=csv_file)

方法3:使用自定义Data Feed(最灵活,但复杂)

对于需要特殊处理的场景,可以创建完全自定义的Data Feed。

classTushareDirectData(bt.feeds.DataBase):""" 直接连接Tushare的Data Feed(示例) 注意:这需要处理实时数据连接,实际使用较少 """params=(('ts_code','000001.SZ'),('start_date','20200101'),('end_date','20231231'),)def__init__(self):super().__init__()# 初始化tushare连接ts.set_token('你的tushare_token')self.pro=ts.pro_api()self.data_df=Noneself.idx=0defstart(self):"""开始加载数据"""self.data_df=self.pro.daily(ts_code=self.p.ts_code,start_date=self.p.start_date,end_date=self.p.end_date)self.data_df=self.data_df.sort_values('trade_date')self.idx=0def_load(self):"""加载下一行数据"""ifself.idx>=len(self.data_df):returnFalserow=self.data_df.iloc[self.idx]# 设置当前bar的数据self.lines.datetime[0]=bt.date2num(pd.to_datetime(row['trade_date']))self.lines.open[0]=row['open']self.lines.high[0]=row['high']self.lines.low[0]=row['low']self.lines.close[0]=row['close']self.lines.volume[0]=row['vol']self.lines.openinterest[0]=0self.idx+=1returnTrue

完整的多股票回测示例

defmulti_stock_backtest():"""多股票回测示例"""cerebro=bt.Cerebro()# 股票列表stocks=['000001.SZ','000002.SZ','000858.SZ']forstock_codeinstocks:try:# 获取数据df=get_tushare_data(stock_code,'20200101','20231231')ifnotdf.empty:# 创建数据源data=TusharePandasData(dataname=df,name=stock_code)cerebro.adddata(data)print(f"已添加:{stock_code}")else:print(f"跳过{stock_code},无数据")exceptExceptionase:print(f"获取{stock_code}数据失败:{e}")iflen(cerebro.datas)==0:print("没有可用的数据")return# 添加策略cerebro.addstrategy(SmaCrossStrategy)# 设置初始资金和佣金cerebro.broker.setcash(100000.0)cerebro.broker.setcommission(commission=0.001)# 运行回测print(f"初始资金:{cerebro.broker.getvalue():.2f}")cerebro.run()print(f"最终资金:{cerebro.broker.getvalue():.2f}")# 绘图cerebro.plot()

Tushare数据字段映射表

Tushare字段Backtrader字段说明
trade_datedatetime交易日期
openopen开盘价
highhigh最高价
lowlow最低价
closeclose收盘价
volvolume成交量
amount-成交额(需特殊处理)
pct_chg-涨跌幅(可添加为额外字段)

实用技巧和注意事项

1.数据预处理

defpreprocess_tushare_data(df):"""数据预处理"""# 1. 处理缺失值df=df.fillna(method='ffill')# 2. 处理异常值df=df[(df['High']>=df['Low'])&(df['Volume']>0)]# 3. 添加额外指标df['Returns']=df['Close'].pct_change()# 4. 确保索引是datetimedf.index=pd.to_datetime(df.index)returndf

2.使用缓存提高效率

importpickleimporthashlibfromfunctoolsimportlru_cache@lru_cache(maxsize=10)defget_cached_tushare_data(ts_code,start_date,end_date):"""带缓存的数据获取"""cache_key=f"{ts_code}_{start_date}_{end_date}"cache_file=f"cache/{hashlib.md5(cache_key.encode()).hexdigest()}.pkl"ifos.path.exists(cache_file):withopen(cache_file,'rb')asf:returnpickle.load(f)else:df=get_tushare_data(ts_code,start_date,end_date)os.makedirs('cache',exist_ok=True)withopen(cache_file,'wb')asf:pickle.dump(df,f)returndf

3.处理复权数据

defget_adj_data(ts_code,start_date,end_date):"""获取复权数据"""ts.set_token('你的token')pro=ts.pro_api()# 获取复权因子df_adj=pro.adj_factor(ts_code=ts_code,trade_date='')# 获取前复权数据df=pro.pro_bar(ts_code=ts_code,adj='qfq',# qfq:前复权, hfq:后复权start_date=start_date,end_date=end_date)# ... 后续处理returndf

4.常见问题解决

问题1:数据时间范围不正确

# 确保数据包含回测所需的时间范围start_date='20190101'# 比回测开始时间早,用于计算指标end_date='20231231'

问题2:成交量单位不一致

# Tushare的成交量单位是"手",需要转换为"股"df['Volume']=df['Volume']*100# 1手 = 100股

问题3:非交易日数据缺失

# 填充非交易日df=df.asfreq('D')# 设置为每日频率df=df.fillna(method='ffill')# 向前填充

5.优化建议

  1. 使用Tushare Pro:免费版有频率限制,Pro版更稳定
  2. 批量下载数据:避免在循环中频繁调用API
  3. 本地缓存:减少API调用次数
  4. 错误处理:添加重试机制
  5. 数据验证:检查数据完整性和准确性

总结

使用Tushare数据配合Backtrader的最佳实践

  1. 使用PandasData方法(方法1),灵活且高效
  2. 做好数据预处理缓存
  3. 注意数据字段映射单位转换
  4. 添加适当的错误处理日志记录

这样就能充分利用 Tushare 丰富的数据和 Backtrader 强大的回测功能了。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/29 5:27:31

21、邮件配置中的重写规则与特殊 m4 配置详解

邮件配置中的重写规则与特殊 m4 配置详解 1. 重写规则理解 重写规则在邮件处理中起着核心作用,它主要用于匹配输入地址并根据特定模式进行重写。下面通过几个测试来详细说明其工作原理。 1.1 模板键值测试 模板使用 @ 加上 $2 的值作为键。例如,当键为 @imaginary.c…

作者头像 李华
网站建设 2026/7/26 8:54:02

多线程相关面试题-线程安全相关问题-锁相关问题

问题 1&#xff1a;什么是进程&#xff1f;什么是线程&#xff1f;二者的核心区别是什么&#xff1f; 问题 2&#xff1a;Java 中创建线程的三种方式是什么&#xff1f;分别举例说明。问题 3&#xff1a;start () 方法和 run () 方法的区别是什么&#xff1f;问题 4&#xff1a…

作者头像 李华
网站建设 2026/7/28 15:09:04

在亚马逊云上解决RDS、MariaDB 与 Aurora MySQL复制延迟实战指南

在高吞吐量的数据库系统中&#xff0c;复制延迟&#xff08;Replica Lag&#xff09;一直是个棘手的难题。在 MySQL 生态圈内&#xff0c;传统的异步复制架构由于其单线程应用事务的性能瓶颈&#xff0c;严重限制了从库&#xff08;Replica&#xff09;的处理能力 (1)。特别是在…

作者头像 李华
网站建设 2026/7/29 14:52:11

Java八股文合集来了,彻底解决一线大厂面试难题

纵观今年的技术招聘市场&#xff0c; Java 依旧是当仁不让的霸主 &#xff01;即便遭受 Go 等新兴语言不断冲击&#xff0c;依旧岿然不动。究其原因&#xff1a; Java 有着极其成熟的生态&#xff0c;这个不用我多说&#xff1b;Java 在 运维、可观测性、可监 控性方面都有着非…

作者头像 李华
网站建设 2026/7/29 12:22:20

5个实用技巧:轻松在Vim中查看文件属性

5个实用技巧&#xff1a;轻松在Vim中查看文件属性 【免费下载链接】vim-galore :mortar_board: All things Vim! 项目地址: https://gitcode.com/gh_mirrors/vi/vim-galore 作为一名Vim用户&#xff0c;你是否曾经需要快速了解文件的修改时间、大小或权限信息&#xff1f…

作者头像 李华
网站建设 2026/7/29 14:34:45

Unity网络请求终极指南:RestClient快速上手与实战技巧

在Unity开发中&#xff0c;处理网络请求是每个开发者都会遇到的挑战。传统的UnityWebRequest虽然功能强大&#xff0c;但代码结构往往复杂冗长。RestClient for Unity应运而生&#xff0c;这款基于Promise的REST和HTTP客户端彻底改变了Unity异步编程的游戏规则&#xff0c;让HT…

作者头像 李华