选用工具
backtrader
注意事项:
1 每月定投 1000元 找当月最近的交易日
2 要设置开始与结束日期
代码如下
import akshare as ak
import pandas as pd
import backtrader as bt
import datetime
# 获取沪深 300 ETF 数据
def fetch_etf_data(symbol="510300"):
# 使用 akshare 的 fund_etf_hist_em 接口获取 ETF 数据
df = ak.fund_etf_hist_em(symbol=symbol, period="daily", adjust='qfq')
# 转换日期格式
df['日期'] = pd.to_datetime(df['日期']) # 假设日期列名为 '日期'
df.set_index('日期', inplace=True)
# 重命名列以符合 Backtrader 的格式要求
df.rename(columns={
'开盘': 'Open', # 假设开盘价列名为 '开盘'
'最高': 'High', # 假设最高价列名为 '最高'
'最低': 'Low', # 假设最低价列名为 '最低'
'收盘': 'Close', # 假设收盘价列名为 '收盘'
'成交量': 'Volume' # 假设成交量列名为 '成交量'
}, inplace=True)
return df
# 定义定投策略
class DingTouStrategy(bt.Strategy):
params = (
('monthday', 1), # 每月定投日期(1 表示每月 1 号)
('amount', 1000), # 每次定投金额
)
def __init__(self):
self.last_month = -1
def next(self):
current_date = self.data.datetime.date()
current_month = current_date.month
# 如果当前月份已经处理过,跳过
if current_month == self.last_month:
return
# 检查当前日期是否为定投日
if current_date.day >= self.params.monthday:
# 如果当前日期是交易日,执行定投
if self.data.close[0] > 0: # 确保当前日期是交易日
self.execute_ding_tou(current_date)
self.last_month = current_month
def execute_ding_tou(self, current_date):
price = self.data.close[0]
size = int(self.params.amount / price)
if size > 0:
self.buy(size=size)
print(f'{current_date}: 定投买入 {size} 份,价格 {price:.3f}')
# 主函数
def main():
# 获取沪深 300 ETF 数据
etf_data = fetch_etf_data(symbol="510300")
# 创建回测引擎
cerebro = bt.Cerebro()
# 加载沪深 300 ETF 数据
data = bt.feeds.PandasData(
dataname=etf_data, # 使用 akshare 获取的数据
fromdate=datetime.datetime(2012, 5, 1), # 沪深 300 ETF 上市时间
todate=datetime.datetime(2025, 1, 1), # 结束日期
timeframe=bt.TimeFrame.Days, # 日线数据
compression=1
)
# 将数据添加到引擎
cerebro.adddata(data)
# 添加策略到引擎
cerebro.addstrategy(DingTouStrategy)
# 设置初始资金
initial_cash = 152000 # 初始资金 15.2 万元
cerebro.broker.set_cash(initial_cash)
# 设置交易手续费(假设为 0.1%)
cerebro.broker.setcommission(commission=0.000)
# 运行回测
print('初始资金: %.2f' % cerebro.broker.getvalue())
cerebro.run()
print('最终资金: %.2f' % cerebro.broker.getvalue())
# 绘制回测结果
cerebro.plot()
# 运行主函数
if __name__ == "__main__":
main()
测试结果
1 cash代表现金
2 value代表总价值 就是股票价值+剩余现金
3 测试结果表明12年累计投入本金15.2万元,最后得到收益20.9万元 累计收益率37% 每年不到3%