本文中的例子来自于优矿的新用户引导中提供的代码;
记录在优矿这个平台一下学习的回测和取数据用到的基本方法
首先第一个策略是新用户引导里面给的,大概干了这么一件事:
- 回测2017-01-01到2018-01-01这段时间的数据
- 在沪深300这个池子里的所有股票中,每天去找市盈率PE最低的100只股票,每天买10000股(100手)
- 如果当天仓里有某一只之前买入的股票不在当天PE最低的100只股票里了,就把这只股票卖出,保证随时仓里都有100只股票(除非钱不够了),而且这100只一定是当天PE最低的100只
- 回测使用天级别,即一天只交易一次
代码的理解分析都写在注释里了
# 先会初始化一些回测用到的参数,这里参数名应该是预定义好的, 有一些有初始值,比如start,end什么的不设也可以;
# 这里的benchmark就是最后回测结果里的基准值,如果把这个值设置为上证综合指数,那就能知道自己有没有跑赢大盘,具体成绩怎么样了。
# 上证综指的secid是000001.ZICN,这里取的是沪深300作为基准,但是这里不知道为啥是HS300,这个代码我没找到在哪儿
# 所有的板块指数在这里可以找到 https://uqer.datayes.com/help/appendixIndex/#%E6%9D%BF%E5%9D%97%E6%8C%87%E6%95%B0%E5%88%97%E8%A1%A8
start = '2017-01-01' # 回测起始时间
end = '2018-01-01' # 回测结束时间
universe = DynamicUniverse('HS300') # 证券池,支持股票、基金、期货、指数四种资产
benchmark = 'HS300' # 策略参考标准
freq = 'd' # 策略类型,'d'表示日间策略使用日线回测,'m'表示日内策略使用分钟线回测
refresh_rate = 1 # 调仓频率,表示执行handle_data的时间间隔,若freq = 'd'时间间隔的单位为交易日,若freq = 'm'时间间隔为分钟
# 配置账户信息,支持多资产多账户
# 这里的account_type支持四种类型:'security'股票和场内基金、 'futures'期货、'otc_fund'场外基金(不含货币基金), 'index'指数 。
# 这部分其他参数在这里 https://uqer.datayes.com/help/faq#AccountConfig%E8%B4%A6%E6%88%B7%E9%85%8D%E7%BD%AE
accounts = {
'fantasy_account': AccountConfig(account_type='security', capital_base=10000000)
}
# 这个初始化应该全局只会调用一次
def initialize(context):
pass
# 每个单位时间(如果按天回测,则每天调用一次,如果按分钟,则每分钟调用一次)调用一次
def handle_data(context):
# 先拿到前一天的时间
previous_date = context.previous_date.strftime('%Y-%m-%d')
# 获取因子PE的的历史数据集,截止到前一个交易日
# 这里先用history这个方法去查股票的历史数据
# 这个hitory的入参有:
# symbol表示需要查询的股票,可以是一个list,这里传的是一个universe,应该本质也是一个list,这里一定要是上面初始化的时候定义的universe中存在的股票
# attribute表示你要查询股票数据的哪一个参数,这里选的PE,市盈率(Price Earnings Ratio),这个PE差不多就等于公司股票价格除以公司盈利的钱;
# 所有可以选择的因子在这里 https://uqer.datayes.com/help/appendixFactors/
# time_range这个参数要和freq一起用,freq表示单位,可以设置1d,1m,5m,30m这些,然后time_range就表示你要获取多少个freq的数据,这里freq没设,估计默认是1d,不确定
# style这个表示输出的格式,s=symbol, t=time, a=attribution,不同的组合输出的格式会变,例如ast就表示返回的字典中的键是attribute,其值是列为symbol、行为time的DataFrame,其他以此类推。
# 然后这里是按tas排序的,就是key为时间,所以这里[previous_date]取了前一天的数据,得到的就是一个二维as维度的表格
hist = context.history(symbol=context.get_universe(exclude_halt=True), attribute='PE', time_range=1,freq="1d", style='tas')[previous_date]
# 将因子值从小到大排序,并取PE最小的100支股票作为目标持仓
signal = hist['PE'].order(ascending=True)
# 因为这里是一个as维度的表格,所以取index实际上就是取的s这个维度,就是取股票的代码
target_position = signal[:100].index
# 获取当前账户信息
account = context.get_account('fantasy_account')
# 这个get_positions是获得当前账户持仓的所有股票list
current_position = account.get_positions(exclude_halt=True)
# 卖出当前持有,但目标持仓没有的部分
for stock in set(current_position).difference(target_position):
# 这个order_to,入参第一个是要卖的股票,第二个参数是要卖到还剩多少股
# 这里的策略是要卖就一次性全卖完,所以就是卖到还剩0股
account.order_to(stock, 0)
# 根据目标持仓权重,逐一委托下单
for stock in target_position:
# 这里的order方法,入参第一个是要买的股票,第二个参数是要买多少股
account.order(stock, 10000)
pass;