5.2 Joseph Piotroski 9 F-Score Value Investing Model · 基本面选股系统:Piotroski F-Score ranking system

来源:https://uqer.io/community/share/56710b1d228e5b8d84f00ac7

  1. from CAL.PyCAL import *
  2. import numpy as np
  3. from pandas import DataFrame , Series
  4. start = '2014-01-01' # 回测起始时间
  5. end = '2015-01-01' # 回测结束时间
  6. benchmark = 'HS300' # 策略参考标准
  7. universe = set_universe('HS300') # 证券池,支持股票和基金
  8. capital_base = 100000 # 起始资金
  9. csvs = []
  10. security_base = {}
  11. commission = Commission(buycost=0.0008, sellcost=0.0018) # 佣金万八
  12. slippage = Slippage()
  13. freq = 'd' # 策略类型,'d'表示日间策略使用日线回测,'m'表示日内策略使用分钟线回测
  14. refresh_rate = 1 # 调仓频率,表示执行handle_data的时间间隔,若freq = 'd'时间间隔的单位为交易日,若freq = 'm'时间间隔为分钟
  15. cal = Calendar('China.SSE')
  16. def initialize(account): # 初始化虚拟账户状态
  17. pass
  18. def handle_data(account): # 每个交易日的买入卖出指令
  19. today = account.current_date.strftime('%Y%m%d')
  20. yesterday = cal.advanceDate(account.current_date, '-1B', BizDayConvention.Following).strftime('%Y%m%d')
  21. lastyear = cal.advanceDate(account.current_date, '-1Y', BizDayConvention.Following).strftime('%Y%m%d')
  22. # 去除ST股
  23. try:
  24. STlist = DataAPI.SecSTGet(secID=account.universe, beginDate=yesterday, endDate=yesterday, field=['secID']).tolist()
  25. account.universe = [s for s in account.universe if s not in STlist]
  26. except:
  27. pass
  28. # 去除流动性差的股票
  29. tv = account.get_attribute_history('turnoverValue', 20)
  30. mtv = {sec: sum(tvs)/20. for sec,tvs in tv.items()}
  31. account.universe = [s for s in account.universe if mtv.get(s, 0) >= 10**7]
  32. # 去除新上市或复牌的股票
  33. opn = account.get_attribute_history('openPrice', 1)
  34. account.universe = [s for s in account.universe if not (np.isnan(opn.get(s, 0)[0]) or opn.get(s, 0)[0] == 0)]
  35. # 调仓部分注意仓位控制,尽量满足80%股票仓位和单只股票不超过10%的条件
  36. #return
  37. buylist = []
  38. selllist = []
  39. getData_yesterday = Series()
  40. getData_lastyear = Series()
  41. #取上一个交易日的数据,用于指标打分
  42. getData_yesterday = DataAPI.MktStockFactorsOneDayGet(tradeDate=yesterday,secID=account.universe,field=['secID','LFLO','ROA','OperCashGrowRate','CurrentRatio','DebtEquityRatio','GrossIncomeRatio','TotalAssetsTRate'],pandas="1")
  43. getData_yesterday.drop_duplicates('secID', inplace = True)
  44. getData_yesterday = getData_yesterday.sort('LFLO', ascending=True)[0:100]
  45. getData_yesterday.set_index('secID',inplace=True)
  46. getData_yesterday.dropna(inplace = True)
  47. #取一年前的数据,用于指标打分
  48. getData_lastyear = DataAPI.MktStockFactorsOneDayGet(tradeDate=lastyear,secID=account.universe,field=['secID','LFLO','ROA','OperCashGrowRate','CurrentRatio','DebtEquityRatio','GrossIncomeRatio','TotalAssetsTRate'],pandas="1")
  49. getData_lastyear.drop_duplicates('secID', inplace = True)
  50. getData_lastyear.set_index('secID',inplace=True)
  51. getData_lastyear.dropna(inplace = True)
  52. totallist = list(set(getData_yesterday.index)&set(getData_lastyear.index))
  53. for s in totallist:
  54. ROA1 = getData_yesterday[s]['ROA']>0
  55. ROA2 = getData_yesterday[s]['ROA']>getData_lastyear[s]['ROA']
  56. OperCashGrowRate = getData_yesterday[s]['CurrentRatio']>0
  57. CurrentRatio = getData_yesterday[s]['CurrentRatio']>getData_lastyear[s]['CurrentRatio']
  58. DebtEquityRatio = getData_yesterday[s]['DebtEquityRatio']<getData_lastyear[s]['DebtEquityRatio']
  59. GrossIncomeRatio = getData_yesterday[s]['GrossIncomeRatio']>getData_lastyear[s]['GrossIncomeRatio']
  60. TotalAssetsTRate = getData_yesterday[s]['TotalAssetsTRate']>getData_lastyear[s]['TotalAssetsTRate']
  61. Scores = int(ROA1)+int(ROA2)+int(OperCashGrowRate)+int(CurrentRatio)+int(DebtEquityRatio)+int(GrossIncomeRatio)+int(TotalAssetsTRate)
  62. if Scores>=6:
  63. buylist.append(s)
  64. for s in account.valid_secpos:
  65. if s not in buylist:
  66. order_to(s, 0)
  67. for s in buylist:
  68. if len(buylist)>=10:
  69. order(s, account.referencePortfolioValue/len(buylist)/account.referencePrice[s])
  70. else:
  71. order_pct_to(s, 0.1)
  72. for s in account.valid_secpos:
  73. if account.referencePrice[s] * account.valid_secpos[s] / account.referencePortfolioValue >0.1:
  74. order_pct_to(s, 0.1)