user-defined package

Const Variable

  1. 获取数据,清洗数据
  2. ```py
  3. def data_for_acb(ticker="000001", tstart=2010, tend=2015):
  4. """获取,清洗 ACB 模型所需要的数据。
  5. ACB 模型需要数据:
  6. 负债合计[TLiab]
  7. 资产总计[TAssets]
  8. 未分配利润[retainedEarnings]
  9. 净利润[NIncome]
  10. 营运资本 = 资产总计 - 负债合计
  11. """
  12. bs_data = DataAPI.FdmtBSGet(ticker=ticker, beginYear=tstart-1, endYear=tend,
  13. field=['secID', 'endDate', 'publishDate', 'TLiab', 'TAssets', 'retainedEarnings'])
  14. is_data = DataAPI.FdmtISGet(ticker=ticker, beginYear=tstart-1, endYear=tend,
  15. field=['secID', 'endDate', 'publishDate', 'NIncome'])
  16. bs_data = bs_data.drop_duplicates('endDate')
  17. is_data = is_data.drop_duplicates('endDate')
  18. data = is_data.merge(bs_data, on=['secID', 'endDate'])
  19. # calculate TAssets diff of current and last report
  20. pre_TAssets = []
  21. length = len(data)
  22. for index, number in enumerate(data.TAssets):
  23. if index + 1 == length:
  24. last_number = index
  25. else:
  26. last_number = index + 1
  27. pre_TAssets.append(data.TAssets[last_number])
  28. data['TAssetsPre'] = pre_TAssets
  29. return data
  30. def data_for_acbel(ticker="000001", tstart=2010, tend=2015):
  31. """获取,清洗 ACB 模型所需要的数据。
  32. ACB 模型需要数据:
  33. 负债合计[TLiab]
  34. 资产总计[TAssets]
  35. 未分配利润[retainedEarnings]
  36. 净利润[NIncome]
  37. 营业总收入[tRevenue]
  38. 总市值[marketValue]
  39. """
  40. bs_data = DataAPI.FdmtBSGet(ticker=ticker, beginYear=tstart-1, endYear=tend,
  41. field=['secID', 'endDate', 'publishDate', 'TLiab', 'TAssets', 'retainedEarnings'])
  42. is_data = DataAPI.FdmtISGet(ticker=ticker, beginYear=tstart-1, endYear=tend,
  43. field=['secID', 'endDate', 'publishDate', 'NIncome', 'tRevenue'])
  44. market_data = DataAPI.MktEqudGet(ticker=ticker, field=['secID', 'tradeDate', 'marketValue'])
  45. market_data.rename(columns={'tradeDate': 'endDate'}, inplace=True)
  46. bs_data = bs_data.drop_duplicates('endDate')
  47. is_data = is_data.drop_duplicates('endDate')
  48. data = is_data.merge(bs_data, on=['secID', 'endDate'])
  49. endDate = list(data.endDate)
  50. data = data.merge(market_data, on=['secID', 'endDate'], how='outer')
  51. data.marketValue = data.marketValue.fillna(method='ffill')
  52. data = data[data.endDate.isin(endDate)]
  53. # calculate TAssets diff of current and last report
  54. pre_TAssets = []
  55. length = len(data)
  56. for index, number in enumerate(data.TAssets):
  57. if index + 1 == length:
  58. last_number = index
  59. else:
  60. last_number = index + 1
  61. pre_TAssets.append(data.TAssets[last_number])
  62. data['TAssetsPre'] = pre_TAssets
  63. return data

测试:获取数据,清洗数据

  1. data_for_acb("002056").head(5)
secIDendDatepublishDate_xNIncomepublishDate_yTLiabTAssetsretainedEarningsTAssetsPre
0002056.XSHE2015-09-302015-10-282.657156e+082015-10-281.672345e+095.129504e+091.401169e+094.820643e+09
1002056.XSHE2015-06-302015-08-271.482967e+082015-08-271.486623e+094.820643e+091.283617e+094.721675e+09
2002056.XSHE2015-03-312015-04-276.872527e+072015-04-271.466576e+094.721675e+091.204153e+094.782852e+09
3002056.XSHE2014-12-312015-03-283.814308e+082015-10-281.484829e+094.782852e+091.250498e+094.809435e+09
4002056.XSHE2014-09-302015-10-289.175491e+072014-10-241.630937e+094.809435e+091.170975e+094.658186e+09
  1. data_for_acbel("002056").head(5)
secIDendDatepublishDate_xNIncometRevenuepublishDate_yTLiabTAssetsretainedEarningsmarketValueTAssetsPre
0002056.XSHE2015-09-302015-10-282.657156e+082.882585e+092015-10-281.672345e+095.129504e+091.401169e+0977906640004.820643e+09
1002056.XSHE2015-06-302015-08-271.482967e+081.800482e+092015-08-271.486623e+094.820643e+091.283617e+09128529520004.721675e+09
2002056.XSHE2015-03-312015-04-276.872527e+078.511258e+082015-04-271.466576e+094.721675e+091.204153e+09120640240004.782852e+09
3002056.XSHE2014-12-312015-03-283.814308e+083.668800e+092015-10-281.484829e+094.782852e+091.250498e+0990192550004.809435e+09
4002056.XSHE2014-09-302015-10-289.175491e+079.342650e+082014-10-241.630937e+094.809435e+091.170975e+0991877240004.658186e+09

计算 Z-score

  1. def zscore_ACB(ticker=None, tstart=2010, tend=2015, coef=[0.517, -0.460, 18.640, 0.388, 1.158]):
  2. # step 1. get data and pre-calculate the factor
  3. ticker = data_for_acb(ticker, tstart, tend)
  4. ticker['x0'] = 1
  5. ticker['x1'] = ticker['TLiab'] / ticker['TAssets']
  6. ticker['x2'] = ticker['NIncome'] * 2 / (ticker['TAssets'] + ticker['TAssetsPre'])
  7. ticker['x3'] = (ticker['TAssets'] - ticker['TLiab']) / ticker['TAssets']
  8. ticker['x4'] = ticker['retainedEarnings'] / ticker['TAssets']
  9. # step 2. calculate zscore
  10. tmp = ticker[['x0', 'x1', 'x2', 'x3', 'x4']] * coef
  11. ticker['zscore'] = tmp.sum(axis=1)
  12. # step 3. build result
  13. ticker.sort('endDate', ascending=True, inplace=True)
  14. return ticker[['secID', 'endDate', 'NIncome', 'TLiab', 'TAssets',
  15. 'retainedEarnings', 'x0', 'x1', 'x2', 'x3', 'x4', 'zscore']]
  16. def zscore_ACBEL(ticker=None, tstart=2010, tend=2015, coef=[0.2086, 4.3465, 4.9601]):
  17. # step 1. get data and pre-calculate the factor
  18. ticker = data_for_acbel(ticker, tstart, tend)
  19. ticker['x0'] = ticker['marketValue'] / ticker['TLiab']
  20. ticker['x1'] = ticker['tRevenue'] / ticker['TAssets']
  21. ticker['x2'] = (ticker['TAssets'] - ticker['TAssetsPre']) / ticker['TAssetsPre']
  22. # step 2. calculate zscore
  23. tmp = ticker[['x0', 'x1', 'x2']] * coef
  24. ticker['zscore'] = tmp.sum(axis=1)
  25. # step 3. build result
  26. ticker.sort('endDate', ascending=True, inplace=True)
  27. return ticker[['secID', 'endDate', 'NIncome', 'TLiab', 'tRevenue', 'TAssets',
  28. 'retainedEarnings', 'marketValue', 'TAssetsPre', 'x0', 'x1', 'x2', 'zscore']]
  29. def get_ticker(bond=None):
  30. """Get the ticker number of a bond.
  31. """
  32. # bondID -> partyID -> ticker
  33. partyID = None
  34. try:
  35. data = DataAPI.BondGet(ticker=bond)
  36. partyID = data['partyID'][0]
  37. except:
  38. return 'Cannot find this bond in DataAPI'
  39. ticker = None
  40. try:
  41. data = DataAPI.SecIDGet(partyID=str(partyID))
  42. ticker = data['ticker'][0]
  43. except:
  44. return 'Cannot find the ticker for this bond in DataAPI, maybe the issuer is not listed'
  45. return ticker

测试:计算 Z-score

  1. zscore_ACB("002506").head(5)
secIDendDateNIncomeTLiabTAssetsretainedEarningsx0x1x2x3x4zscore
21002506.XSHE2009-12-311.699573e+087.039600e+081.262617e+092.845660e+0810.5575400.1346070.4424600.2253783.202272
20002506.XSHE2010-09-301.051847e+081.131338e+091.848964e+094.404125e+0810.6118770.0676090.3881230.2381941.922180
19002506.XSHE2010-12-312.194191e+081.398571e+094.466591e+094.881275e+0810.3131180.0694850.6868820.1092842.061233
18002506.XSHE2011-03-313.719796e+071.841932e+094.946957e+095.261166e+0810.3723360.0079030.6276640.1063520.859727
17002506.XSHE2011-06-301.313367e+082.631518e+095.728841e+095.177251e+0810.4593460.0246050.5406540.0903721.078754
  1. zscore_ACBEL("002506").head(5)
secIDendDateNIncomeTLiabtRevenueTAssetsretainedEarningsmarketValueTAssetsPrex0x1x2zscore
21002506.XSHE2009-12-311.699573e+087.039600e+081.318242e+091.262617e+092.845660e+08117328360001.262617e+0916.6669061.0440550.0000008.014703
20002506.XSHE2010-09-301.545466e+081.131338e+091.646226e+091.848964e+094.404125e+08117328360001.262617e+0910.3707590.8903500.4643908.336670
19002506.XSHE2010-12-312.194191e+081.398571e+092.686649e+094.466591e+094.881275e+08117328360001.848964e+098.3891630.6014991.41572611.386537
18002506.XSHE2011-03-313.719796e+071.841932e+096.502649e+084.946957e+095.261166e+08125869000004.466591e+096.8335310.1314470.1075472.530253
17002506.XSHE2011-06-301.313367e+082.631518e+091.797884e+095.728841e+095.177251e+08101749600004.946957e+093.8665750.3138300.1580532.954592
  1. a = zscore_ACBEL("002506")
  2. a.head(3)
secIDendDateNIncomeTLiabtRevenueTAssetsretainedEarningsmarketValueTAssetsPrex0x1x2zscore
21002506.XSHE2009-12-311.699573e+087.039600e+081.318242e+091.262617e+092.845660e+08117328360001.262617e+0916.6669061.0440550.0000008.014703
20002506.XSHE2010-09-301.051847e+081.131338e+096.184189e+081.848964e+094.404125e+08117328360001.262617e+0910.3707590.3344680.4643905.920527
19002506.XSHE2010-12-312.194191e+081.398571e+092.686649e+094.466591e+094.881275e+08117328360001.848964e+098.3891630.6014991.41572611.386537

作图分析

  1. def zscore_plot(dataframe, upper_limit, low_limit):
  2. ax = dataframe.plot('endDate', ['zscore'], figsize=(20, 10), style='g-', title='zscore curve',)
  3. axhspan(low_limit, dataframe.zscore.min(), facecolor='maroon', alpha=0.1)
  4. axhspan(upper_limit, dataframe.zscore.max(), facecolor='yellow', alpha=0.2)
  5. ax.legend()
  6. return ax

测试:作图分析

这里,我们以 11超日债[112061] 来做测试,看看当前这个模型表现怎么样。

  • step 1: 调用 get_ticker 函数通过债券代码获取发行人上市代码,在发行人已上市的前提下;
  • step 2: 调用 zscore_ACBELzscore_ACB 计算发行人的 Z-score 值;
  • step 3: 调用 zscore_plot 绘制 Z-score 曲线;
  1. ticker = get_ticker("112061")
  2. df = zscore_ACBEL(ticker)
  3. zscore_plot(df, 1.5408, 1.5408)
  4. <matplotlib.axes.AxesSubplot at 0x5220a10>

user-defined package - 图1

  1. ticker = get_ticker("112061")
  2. df = zscore_ACB(ticker)
  3. zscore_plot(df, 0.9, 0.5)
  4. <matplotlib.axes.AxesSubplot at 0x525c610>

user-defined package - 图2