量化交易6-backtrader编写策略的时数据获取

上一篇文章讲到了均线的指标的运用,策略是比较简单的策略,就是使用5日均线和10均线的价格做比较,然后进行全仓的买卖,本文会继续沿用上文所使用的策略。不同的是,本文笔者会较为详细的介绍,编写策略过程中,数据的获取方式,比如指标的定义方式,backtrader而言,指标有两种方式,一种是backtrader本身就支持的定义好的指标,比如5日或者10均线,具体backtrader支持了多少指标后续笔者会为大家继续整理,另一种就是自定义指标。

以编写5日均线对比10日均线而言,编写策略中所需要的常用数据做个简单的介绍:

# 初始化时
设置初始资金,cerebro.broker.setcash( 100000000.0)

# 策略中调用
获取当前可用资金,cerebro.broker.getcash()

self.dataclose[0] # 当日的收盘价
self.dataclose[-1] # 昨天的收盘价
self.dataclose[-2] # 前天的收盘价

当前总资产self.broker.getvalue
当前持仓量, self.getposition(self.data).size
当前持仓成本, self.getposition(self.data).price

Broker 在每次交易后更新 cash 外,还会同时更新当前总资产 value 和当前持仓 position,通常在 Strategy 中调用上述方法进行查询

指标数据使用:

均线是backtrader本身就支持的指标:

# 策略参数
    params = dict(
        period5=5,  # 5均线周期
        period10=10,  # 10均线周期
        look_back_days=30,
        printlog=False
    )

self.mas[data._id] = bt.ind.SMA(data.close, period=self.p.period5)   #5日均线
self.mas10[data._id] = bt.ind.SMA(data.close, period=self.p.period10) #10日均线

其中bt.ind.SMA是backtrader就已经定义好的均线的获取方式,backtrader支持的更多的指标请读者自行在backtrader查看,关于如果自定义指标,后续笔者会继续为大家整理。

通过上述的数据就能够获取指标,然后结合之前的策略构建步骤,就能实现策略:5日均线高于10均,全仓买入,反之全仓卖出。

代码如下:

import tushare as ts
import pandas as pd

import datetime  # For datetime objects
import os.path  # To manage paths
import sys  # To find out the script name (in argv[0])
# Import the backtrader platform
import backtrader as bt


class MyStrategy(bt.Strategy):
    # 策略参数
    params = dict(
        period5=5,  # 5均线周期
        period10=10,  # 10均线周期
        look_back_days=30,
        printlog=False
    )

    def __init__(self):
        self.mas = dict()
        self.mas10 = dict()
        # 遍历所有股票,计算20日均线
        for data in self.datas:
            self.mas[data._id] = bt.ind.SMA(data.close, period=self.p.period5)
            self.mas10[data._id] = bt.ind.SMA(data.close, period=self.p.period10)

    def next(self):
        # 得到当前的账户价值
        total_value = self.broker.getcash()
        print('剩余的资金->' + str(total_value))
        for data in self.datas:
            # 获取仓位
            pos = self.getposition(data).size
            if self.mas10[data._id][0] < self.mas[data._id][0]:
                p_value = total_value * 0.9 / 10
                size = ((int(total_value / self.data.close[0]))) - ((int(total_value / self.data.close[0])) % 100) - 100
                print('10日均线价格->' + str(self.mas10[data._id][0]) + ',5日均线价格->' + str(self.mas[data._id][0]) + \
                ',持仓数量->' + str(pos) + ',买入数量->' + str(size))
                self.buy(data=data, size=size)

            if pos > 0 and self.mas10[data._id][0] > self.mas[data._id][0]:
                print('10日均线价格->' + str(self.mas10[data._id][0]) + ',5日均线价格->' + str(self.mas[data._id][0]) + \
                ',持仓数量->' + str(pos) + ',卖出数量->' + str(pos))
                self.order = self.sell(data=data, size=pos)

    def log(self, txt, dt=None, doprint=False):
        if self.params.printlog or doprint:
            dt = dt or self.datas[0].datetime.date(0)
            print(f'{dt.isoformat()},{txt}')

    # 记录交易执行情况(可省略,默认不输出结果)
    def notify_order(self, order):
        # 如果order为submitted/accepted,返回空
        if order.status in [order.Submitted, order.Accepted]:
            return
        # 如果order为buy/sell executed,报告价格结果
        if order.status in [order.Completed]:
            if order.isbuy():
                self.log(f'买入:\n价格:{order.executed.price:.2f},\
                成本:{order.executed.value:.2f},\
                数量:{order.executed.size:.2f},\
                手续费:{order.executed.comm:.2f}')
                self.buyprice = order.executed.price
                self.buycomm = order.executed.comm
            else:
                self.log(f'卖出:\n价格:{order.executed.price:.2f},\
                成本: {order.executed.value:.2f},\
                数量:{order.executed.size:.2f},\
                手续费{order.executed.comm:.2f}')
            self.bar_executed = len(self)
            # 如果指令取消/交易失败, 报告结果
        elif order.status in [order.Canceled, order.Margin, order.Rejected]:
            self.log('交易失败')
        self.order = None

    # 记录交易收益情况(可省略,默认不输出结果)
    def notify_trade(self, trade):
        if not trade.isclosed:
            return
        self.log(f'策略收益:\n毛收益 {trade.pnl:.2f}, 净收益 {trade.pnlcomm:.2f}')

pro = ts.pro_api('cbb257058b7cb228769b4949437c27c27e5132e882747dc80f01a5a5')

def ts_get_daily_stock(code, start_dt, end_dt):
    start_dt = start_dt.replace("'", "", 3);
    end_dt = end_dt.replace("'", "", 3);
    # start_dt = '20190101'
    # end_dt=''
    print(code, start_dt, end_dt)
    data = pro.daily(ts_code=code, start_date=start_dt, end_date=end_dt)
    data['trade_date'] = pd.to_datetime(data['trade_date'])
    data['trade_date'] = pd.to_datetime(data['trade_date'])
    data = data.sort_values(by='trade_date')
    data.index = data['trade_date']
    data['openinterest'] = 0
    data['volume'] = data['vol']
    data = data[
        ['open', 'close', 'high', 'low', 'volume']
    ]
    return data


# 读取选股的结果
df = pd.read_csv('stock_alpha.csv')
df.columns = ['ts_code', 'name', 'alpha', 'start_dt', 'end_dt']
min_a = df.sort_values(by='alpha')
min_a = min_a.iloc[:10, :]

code = []
code = min_a['ts_code']  # 股票代码

start_dts = []
start_dts = min_a['start_dt']  # 股票代码起始时间

end_dts = []
end_dts = min_a['end_dt']  # 股票代码结束时间

for i in range(len(code)):
    data = ts_get_daily_stock(code.iloc[i], start_dts.iloc[i], end_dts.iloc[i])  # 字段分别为股票代码、开始日期、结束日期
    data.to_csv(code.iloc[i] + '.csv')

cerebro = bt.Cerebro()
for i in range(len(code)):  # 循环获取股票历史数据
    dataframe = pd.read_csv(code.iloc[i] + '.csv', index_col=0, parse_dates=True)
    dataframe['openinterest'] = 0
    data = bt.feeds.PandasData(dataname=dataframe,
                               fromdate=datetime.datetime(2006, 8, 18),
                               todate=datetime.datetime(2022, 3, 22)
                               )
cerebro.adddata(data)

# 回测设置
startcash = 100000.0
cerebro.broker.setcash(startcash)
# 设置佣金为千分之一
cerebro.broker.setcommission(commission=0.001)
# 添加策略
cerebro.addstrategy(MyStrategy, printlog=True)
cerebro.run()
# 获取回测结束后的总资金
portvalue = cerebro.broker.getvalue()
pnl = portvalue - startcash
# 打印结果
print(f'总资金: {round(portvalue,2)}')
print(f'净收益: {round(pnl,2)}')

cerebro.plot()
 

其中用到的csv文件还是从上一章的地址获取

结果为:

总资金: 136632.34
净收益: 36632.34

执行图为:

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
股票回测是量化交易中非常重要的一环,它可以通过历史数据对交易策略进行模拟和评估,从而评估策略的可行性和优劣性。在Python中,有很多开源的量化交易框架可以用来进行股票回测,如zipline、backtrader等。 下面是一个使用zipline框架进行简单交易策略回测的例子: 1. 安装zipline ```python pip install zipline ``` 2. 编写交易策略代码 ```python from zipline.api import order_target_percent, record, symbol def initialize(context): context.asset = symbol('AAPL') def handle_data(context, data): # 获取过去10天的收盘价 prices = data.history(context.asset, 'price', 10, '1d') # 计算平均价 mean_price = prices.mean() # 如果当前价格低于平均价,则买入 if data.current(context.asset, 'price') < mean_price: # 调整持仓比例至100% order_target_percent(context.asset, 1.0) # 否则卖出 else: # 调整持仓比例至0% order_target_percent(context.asset, 0.0) # 记录当前持仓比例 record(position=context.portfolio.positions[context.asset].amount) ``` 3. 运行回测 ```python from zipline import run_algorithm from zipline.api import symbol from datetime import datetime start = datetime(2016, 1, 1) end = datetime(2017, 1, 1) result = run_algorithm( start=start, end=end, initialize=initialize, capital_base=10000, handle_data=handle_data, bundle='quandl' ) ``` 在上述代码中,我们定义了一个简单的交易策略,即如果当前价格低于过去10天的平均价,则买入,否则卖出。然后我们使用zipline框架进行回测,设定回测开始和结束间、初始资本、数据来源等参数,最终得到回测结果。 需要注意的是,这只是一个简单的例子,实际的交易策略可能会更加复杂,需要考虑更多的因素。另外,在进行股票回测,也需要注意避免过度拟合或过度优化,以免出现回测虚高的情况。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大风哥哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值