import pandas as pd
import numpy as np
import talib
import backtrader as bt
import yfinance as yf
# 定义策略类
class BottomVolumeStrategy(bt.Strategy):
params = (
('volume_ratio', 2.5), # 量比
('turnover_rate', 0.03), # 换手率
('stop_loss', 0.95), # 止损点
('take_profit', 1.10), # 止盈点
)
def __init__(self):
# 计算技术指标
self.sma5 = bt.indicators.SimpleMovingAverage(self.data.close, period=5)
self.sma20 = bt.indicators.SimpleMovingAverage(self.data.close, period=20)
self.sma60 = bt.indicators.SimpleMovingAverage(self.data.close, period=60)
self.volume_ratio = self.data.volume / bt.indicators.SimpleMovingAverage(self.data.volume, period=5)
self.turnover_rate = self.data.volume / self.data.capitalization * 100
def next(self):
# 检查是否已经持仓
if self.position:
# 平仓条件:跌破5日均线或达到止盈/止损
if self.data.close[0] < self.sma5[0] or \
self.data.close[0] >= self.params.take_profit * self.position.price or \
self.data.close[0] < = self.params.stop_loss * self.position.price:
self.sell()
else:
# 开仓条件:量比、换手率、均线金叉、股价在60日均线之上
if self.volume_ratio[0] >= self.params.volume_ratio and \
self.turnover_rate[0] >= self.params.turnover_rate and \
self.sma5[0] > self.sma20[0] and \
self.data.close[0] > self.sma60[0]:
self.buy()
# 下载股票数据
def download_data(ticker, start_date, end_date):
data = yf.download(ticker, start=start_date, end=end_date)
data['capitalization'] = data['Close'] * data['Volume'] # 简单计算市值
return data
# 回测函数
def backtest(data):
cerebro = bt.Cerebro()
cerebro.addstrategy(BottomVolumeStrategy)
# 加载数据
data = bt.feeds.PandasData(dataname=data)
cerebro.adddata(data)
# 设置初始资金
cerebro.broker.set_cash(100000)
# 运行回测
print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())
cerebro.run()
print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())
# 绘制结果
cerebro.plot()
# 主程序
if __name__ == '__main__':
# 下载数据
ticker = 'AAPL' # 以苹果股票为例
start_date = '2020-01-01'
end_date = '2023-01-01'
data = download_data(ticker, start_date, end_date)
# 运行回测
backtest(data)
2025-02-18