经典量化交易策略之羊驼

1
回复
4363
查看
[复制链接]

63

主题

36

回帖

1915

积分

管理员

积分
1915
来源: 2019-7-17 21:58:11 显示全部楼层 |阅读模式
 你的选股策略真的有效吗?其实不一定有随机小泽效果好,以前电视台展示过一个策略:羊驼来选股,即每天卖掉持有的股票中收益率最差的一只,然后让羊驼随机选入一只股票来买,结果收货颇丰。人们根据这种情况开始尝试使用羊驼来选股,本文介绍根据每天持有收益率最靠前的股票来选股的策略。
  1. 基本原理
  在这个量化交易策略中,对股票池中的所有股票,每天按照收益率从小到大进行排序,起始时买入num_of_stocks只股票,然后每天在整个股票池中选出收益率前num_of_stocks,如果这些股票未持有则买入,已持有,则继续持有,并把收益率不是排在前num_of_stocks的股票卖掉。
  2.策略实现
  初始资金:20万元
  投资域:沪深300股票池
  回测频率 :按日回测
  回测时间段 :2012年1月2日至2015年10月8日(和股票上市实际时间段的交集 )
  羊驼策略-每天持有收益率前n选股流程
  1.设置策略参数,初始买入的股票数num_of_stocks,收益率计算所用天数period,其中收益率=昨天的收盘价/period天之前的收盘价。
  2.将股票池内的股票按照收益率排序,买入收益率最高的num_of_stocks只股票。
  3.之后的每天都将所有股票按收益率排序,如果股票池中有处于收益率前num_of_stocks而未持有的则买入,并卖掉收益率不处于前num_of_stocks的
  注:在本策略中,如果遇到选中的股票停牌导致无法卖出/买入,当天不卖出/不买入此股票,在第二天多卖一只/多买一只

  1. 源码:
  2.   import random
  3.   import numpy as np
  4.   import pandas as pd
  5.   from pandas import Series,DataFrame
  6.   import scipy.stats as stats
  7.   import math
  8.   # 设置股票池,本程序中为所有沪深300的股票
  9.   stocks = get_index_stocks('000300.XSHG')
  10.   #求出股票池中有多少股票
  11.   num=len(stocks)
  12.   set_universe(stocks)
  13.   #设置benchmark,默认为沪深300
  14.   #set_benchmark('510050.XSHG')
  15.   #设置回测条件
  16.   set_commission(PerTrade(buy_cost=0.0008, sell_cost=0.0015, min_cost=5))set_slippage(FixedSlippage(0))
  17.   #设置初始买入多少只股票
  18.   num_of_stocks=5
  19.   #设置计算几日收益率
  20.   period=5
  21.   #用一个列表来保存每天持有的股票代码
  22.   stockshold=[]
  23.   #判断参数输入是否符合条件,如果不符合,则重置为默认值
  24.   if num_of_stocks>num:
  25.   log.info("too large num_of_stocks")
  26.   num_of_stocks=10
  27.   #预处理数据,将没有数据的股票剔除,同时加入收益率
  28.   #构成一个列索引为股票名,收益率一行的索引为
  29.   #'return'的dataframe,并返回这个dataframe
  30.   def process():
  31.   #取出每只股票period天的收盘价格
  32.   stocks_info=history(period,'1d','close')
  33.   #去除信息不全的数据
  34.   stocks_info.dropna(axis=0,how='any',thresh=None)
  35.   #取出昨天和period天之前的收盘价,计算收益率
  36.   a1=list(stocks_info.iloc[0])
  37.   a2=list(stocks_info.iloc[period-1])
  38.   a1=np.array(a1)
  39.   a2=np.array(a2)
  40.   #用一个dataframe来保存所有股票的收益率信息
  41.   stocks_return=DataFrame(a2/a1,columns=['return'],index=stocks_info.columns)
  42.   stocks_info=stocks_info.T
  43.   #把收益率的数据加到相应的列
  44.   stocks_info=pd.concat([stocks_info,stocks_return],axis=1)
  45.   #将股票信息按照收益率从大到小来存储
  46.   stocks_info=stocks_info.sort(columns=['return'],ascending=[False])
  47.   #返回处理好的dataframe
  48.   return stocks_info
  49.   #股票入池
  50.   def BuyStocks(stocks_info,cash):
  51.   #计算现在持有的股票数
  52.   current_num=len(stockshold)
  53.   stocks_info=stocks_info.T
  54.   #将已持有的股票从股票池中剔除
  55.   for i in range(0,current_num):
  56.   if stockshold[i] in stocks_info.columns:
  57.   del stocks_info[stockshold[i]]
  58.   stocks_info=stocks_info.T
  59.   #计算在每只股票上可以支付的现金
  60.   if num_of_stocks-current_num>0:
  61.   cash=cash/(num_of_stocks-current_num)
  62.   for i in range(0,num_of_stocks-current_num):
  63.   #取得股票当前的价格
  64.   current_price=stocks_info['current_price'][i]
  65.   #判断是否有价格数据
  66.   if math.isnan(current_price)==False:
  67.   #计算可以每只股票可以购买的数量
  68.   num_of_shares=int(cash/current_price)
  69.   if num_of_shares>0:
  70.   order(stocks_info.index[i],+num_of_shares)
  71.   log.info("buying %s" %(stocks_info.index[i]))
  72.   #将购买的股票代码加到stockhold中
  73.   stockshold.append(stocks_info.index[i])
  74.   #股票出池
  75.   def SellStocks(stocks_info):
  76.   stocks_hold=DataFrame()
  77.   stocksremove=[]
  78.   current_num=len(stockshold)
  79.   #用一个dataframe来保存收益率前n的股票的信息
  80.   for i in range(0,num_of_stocks):
  81.   stocks_hold=pd.concat([stocks_hold,stocks_info.iloc[i]],axis=1) #找出目前持有的股票中不处于收益率前n的股票
  82.   for i in range(0,current_num):
  83.   #判断股票是否因缺数据而不在更新后的stocks_info里
  84.   if stockshold[i] in stocks_info.index:
  85.   #如果股票不在收益率前n的股票中
  86.   if stockshold[i] not in stocks_hold.columns:
  87.   #在stocksremove中保存该股票代码,以便从stockshold中删除
  88.   stocksremove.append(stockshold[i])
  89.   #如果该股票未停牌
  90.   if stocks_info['paused'][stockshold[i]]=='False':
  91.   #则将其卖出
  92.   order_target(stockshold[i],0)
  93.   #将收益率不在前n的股票从stockshold中删除
  94.   for i in range(0,len(stocksremove)):
  95.   stockshold.remove(stocksremove[i])
  96.   # 每个单位时间(如果按天回测,则每天调用一次,如果按分钟,则每分钟调用一次)调用一次
  97.   def handle_data(context, data):
  98.   stocks_info=process()
  99.   stocks_num=len(stocks_info.index)
  100.   #用一个列表来保存所有股票是否停牌的信息
  101.   pause=[]
  102.   for i in range(0,stocks_num):
  103.   if data[stocks_info.index[i]].paused==True:
  104.   pause.append('True')
  105.   else:
  106.   pause.append('False')
  107.   #将列表转换成dataframe以便加入到stocks_info中
  108.   paused=DataFrame(pause,columns=['paused'],index=stocks_info.index) stocks_info=pd.concat([stocks_info,paused],axis=1)
  109.   #用一个列表来保存所有股票当前的价格信息
  110.   currentprice=[]
  111.   for i in range(0,stocks_num):
  112.   currentprice.append(data[stocks_info.index[i]].price)
  113.   current_price=DataFrame(currentprice,columns=['current_price'],index=stocks_info.index)
  114.   #将股票是否停牌,当前价格的信息添加到stocks_info中
  115.   stocks_info=pd.concat([stocks_info,current_price],axis=1)
  116.   #取得当前现金
  117.   cash=context.portfolio.cash
  118.   #执行卖出股票的函数
  119.   SellStocks(stocks_info)
  120.   #执行买入股票的函数

  121.   BuyStocks(stocks_info,cash)
复制代码
成本.jpg

回复

使用道具 举报

196

主题

140

回帖

1444

积分

管理员

积分
1444
2019-7-17 23:32:34 显示全部楼层
人有时候不一定有羊驼选股好
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 免费注册
关注微信