5.10 PAMR · PAMR : 基于均值反转的投资组合选择策略 - 修改版

来源:https://uqer.io/community/share/55a4c52bf9f06c6dd3e17f0f

策略思路:

该策略的主要思想是用一个损失函数反映均值反转性质,即如果基于前一期相对价格的预期收益值大于一定阈值,损失值将线性增长;否则,损失为0

策略实现

m个资产每日调仓:对每个资产,收益高于总资产平均收益者,减持;收益低于总资产平均收益者,增持

具体参见文献: http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.421.579&rep=rep1&type=pdf

  1. from CAL.PyCAL import *
  2. from numpy import *
  3. import pandas as pd
  4. import numpy as np
  5. from pandas import DataFrame
  6. import cvxopt
  7. from cvxopt import matrix
  8. from cvxopt.blas import dot
  9. import cvxopt.solvers as cs
  10. # parameters used in updatePAMR
  11. sensitivity = 0.8
  12. C = 600
  13. start = datetime(2012, 12, 1)
  14. end = datetime(2015, 5, 1)
  15. benchmark = 'HS300'
  16. universe = set_universe('SH180')
  17. capital_base = 1e8
  18. refresh_rate = 1
  19. window = 1
  20. tickers = [stk[0:6] for stk in universe]
  21. portfolio = DataFrame(1.0, index = universe, columns = ['prePosition', 'position', 'relative_price'])
  22. def initialize(account):
  23. account.amount = capital_base
  24. account.universe = universe
  25. account.days = 0
  26. def handle_data(account):
  27. today = account.current_date
  28. today_str = today.strftime("%Y%m%d")
  29. for stk in universe:
  30. hist_close = account.get_attribute_history('closePrice', 2)
  31. hist_pre_close = account.get_attribute_history('preClosePrice', 2)
  32. try:
  33. portfolio['relative_price'][stk] = hist_close[stk][-1]/hist_pre_close[stk][-1]
  34. #print stk, today_str, portfolio['relative_price'][stk]
  35. except:
  36. continue
  37. portfolio['relative_price'] = portfolio['relative_price'].fillna(1.0)
  38. portfolio['prePosition'] = portfolio['position']
  39. a = portfolio['prePosition']
  40. b = portfolio['relative_price']
  41. portfolio['position'] = normalizePortfolio(updatePAMR(a, b, sensitivity, C))
  42. for stk in portfolio.index:
  43. try:
  44. stk_amount = capital_base*portfolio['position'][stk]/hist_close[stk][-1]
  45. order_to(stk, stk_amount)
  46. except:
  47. continue
  48. def lossFunction(portfolio, relative_price, sensitivity):
  49. # define a e-insensitive loss function
  50. # portfolio vector: b
  51. # price relative vector: x
  52. # sensitivity parameter: e
  53. # then: loss = max(0, dot(x,b) - e)
  54. portfolio_return = portfolio.transpose().dot(relative_price)
  55. if portfolio_return < sensitivity:
  56. return 0
  57. else:
  58. return portfolio_return - sensitivity
  59. def normalizePortfolio(portfolio):
  60. # original portfolio vector: b_origin
  61. # find b = argmin(|b - b_origin|^2) under condition:
  62. # sum(b_i) = 1 and b_i > 0 for all i
  63. # solve the problems using Quadratic Programming Method:
  64. # http://abel.ee.ucla.edu/cvxopt/userguide/coneprog.html#quadratic-programming
  65. n = portfolio.shape[0]
  66. S = cvxopt.matrix(0.0, (n,n))
  67. S[::n+1] = 1.0
  68. S = S.T*S
  69. pbar = cvxopt.matrix(portfolio.values).T*(S + S.T)
  70. pbar = pbar.T
  71. G = cvxopt.matrix(0.0, (n,n))
  72. G[::n+1] = -1.0
  73. h = cvxopt.matrix(0.0, (n,1))
  74. A = cvxopt.matrix(1.0, (1,n))
  75. b = cvxopt.matrix(1.0)
  76. cvxopt.solvers.options['show_progress'] = False
  77. x = cs.qp(S, -pbar, G, h, A, b)['x']
  78. b = portfolio.copy()
  79. for i in range(0, n):
  80. b.ix[b.index[i]] = x[i]
  81. return b
  82. def updatePAMR(portfolio, relative_price, sensitivity, C):
  83. # update portfolio by PAMR2 methods:
  84. # PAMR: Passive Aggressive Mean Reversion Strategy for Portfolio Selection.
  85. # Bin Li, Peilin Zhao, Steven C.H. Hoi, and V. Gopalkrishnan.
  86. # Machine Learning, 2012, 87(2), 221 - 258.
  87. loss = lossFunction(portfolio, relative_price, sensitivity)
  88. avg_ret = relative_price.sum()/relative_price.shape[0]
  89. tmp = ((relative_price - avg_ret)**2).sum() + 1.0/2/C
  90. tau = loss/tmp
  91. return portfolio - tau*(relative_price - avg_ret)

5.10 PAMR · PAMR : 基于均值反转的投资组合选择策略 - 修改版 - 图1