引言% E5 w# f; x7 J7 L4 E
9 G [: [- {1 J* \
自己平时也在研究一些可转债策略,也会关注一些可转债的研报,近期阅读与研究了光大证券2020年8月发布的一篇研报《可转债轮动策略研究系列之一:着重低转股溢价率的策略占优》;这篇研报的内容还是很不错的,研究转债的小伙伴推荐阅读;今天我们来研究学习一下本篇研报,研报中介绍了三种低价类轮动策略、三种低估值轮动策略、三种高性价比轮动策略一共九种策略,我挑选了其中2个收益高的策略来进行复现
' B. x! F1 E5 l) M" k% g5 \三种低价类轮动策略2 o, M* [- a8 I/ h4 K% i: \ }/ K' v
i6 v& j2 t/ p2 N1 s( l7 Y8 z回测设置:5 g1 X2 o; u1 @( t
1. 每月调仓 1 次,调仓时间为月末最后一个交易日,买入价为月末最后一个交易日收盘价
* t3 w: ~6 ?7 c @2 h% u2. 组合选取择券指标排序在前的 10 只个券' F9 P8 s3 z x, f8 P' G' L
3. 回测时段为 2018 年以来,主要原因为 2018 年 1 月二级市场存量可转债数量首次突破 40 个,之前可选择的标的数量偏少3 b2 N, w1 T; L4 s- R2 P
4. 标的选择范围为债券余额大于 2 亿元(含),初始评级高于 AA-(含)( E! j: n# S1 C* R( k
① 低价轮动策略:每期选择价格最低的标的
$ i7 f% S( d) J+ H3 m② 高到期收益率轮动策略:每期选择到期收益率最高的标的
1 L9 Q# g* U3 Z* T4 \8 A. {③ 低纯债溢价率轮动策略:每期选择到纯债溢价率最低的标的1 a% A+ ^! O! j
0 o) G B* m/ s5 W& Q! c; {
( Z! x& i) o$ ?
回测结论:低价格轮动策略、 高 YTM 轮动策略、低纯债溢价率轮动策略在 2018 年 1 月 1 日至 2020 年 8 月 17 日的收益率(年化)分别为 13.15%、11.08%和 9.62%,与同期中证转债指数的年化涨幅(11.45%)差异不大0 |/ H/ Y( G* P3 g) Q2 T
虽然这几个策略收益不高,但是对于价格能够低于100元面值或者到期收益率较高的标的买入,我们持有者拿着不慌,能睡好觉
7 Q) X4 s7 _4 b% _" U8 y三种低估值轮动策略4 H+ O' U/ D( E# U
$ Z2 M" o- h0 A' T7 _
用转股价值(或称为平价)进行分类,这种方法本质上是弱化纯债价值的差异
7 Z' A3 q0 d; P, W) H将主要的可转债分为低平价(转股价值位于 70 元至 90 元之间)、中平价(转股价值位于90 元至 110 元之间)和高平价可转债(转股价值位于 110 元至 130 元之间)。: a* r1 P1 Q$ [
对于低平价、中平价、高平价三类可转债,转股溢价率是最常见和直观的可转债估值指标,但它又存在较大的缺陷,那就是单纯的依靠溢价率来作为转债股指是不科学的;因为转股溢价率与转股价值具有一定的相关性,我们可以来拟合其相关性,来构建修复后的溢价率,以此为依托来构建可转债轮动策略& I3 m* m: t4 d5 c
研报回测结论
$ ^ B, m( }- x8 t
- q+ j& q; T) z
+ Z; J* _+ J% N# f结论:高平价低估值轮动策略的收益明显高出低、中平价轮动策略,那么我们就来实现这个高平价低估值轮动策略
# s; m/ K0 U5 t* W. a( s6 ^构建原理
7 I+ T- k+ d7 ^2 \* y2 R6 b4 T j! B
9 U$ @% _, o7 d, Q5 N+ d! P4 }2 L7 U% f8 h
/ ? t2 f5 ^) Z/ X1 L/ L
第一:构建高平价可转债转股溢价率与转股价值的相关系数
* d: P/ G# l }: D+ t |根据研报,我们根据选择每个季度末转股价值在110元到130元之间的转债数据(转股价值和转股溢价率)分别拟合构建每个季度的转股溢价率与转股价值的相关系数;然后计算季度系数的平均值
5 _! S$ g2 }& w& z3 a5 d代码如下:
) T8 z! f$ h5 Ndef build_quarter_data(start_time):
' m6 e+ a+ Q( l3 O """* N1 b, ?2 Y3 }1 X6 h% A* A
构建季度高平价可转债转股溢价率与转股价值的相关系数) w+ H$ J' F7 {$ q8 Y
"""
$ ]' c- o" T5 E9 b* M5 U9 p R$ r file_list = []3 b. a* W! R! D, M
path = os.path.join(root_path, r'data\stock\basic_trading_data\convertible')
7 C4 v2 s. m8 q" Y$ S" v' E2 w3 V3 I5 v* C: L
# 系统自带函数os.walk,用于遍历文件夹中的所有文件# T2 o0 d1 J# G5 A& {1 L3 |
for root, dirs, files in os.walk(path):
n4 P' z( f' O' c& L/ R' t if files: # 当files不为空的时候+ R* w4 t+ b' J" n
for f in files:
2 ~* \% ]1 n" Z if '.csv' in f:
+ K" p1 p8 U7 R; d' S8 h+ S file_list.append(os.path.join(path, f))
% N) T; C, |3 C# ]. [5 T$ B # 并行
* V [- U( Z) `+ i5 g) Q$ |7 U8 f with Pool(processes=8) as pool:
$ I6 @/ C2 Z( e. W d7 T% ~ all_df = pool.map(cal_con_quarter, file_list)
a* {5 P2 w5 s- W+ b; w, k all_df = pd.concat(all_df, ignore_index=True)
, a/ ^7 s( q- x0 F: a+ J
; q' L4 W- O- J2 o # 导入上证指数,保证指数数据和股票数据在同一天结束,不然会出现问题。
! N3 h+ u4 d& g$ F/ Q* f2 q index_stock_code = 'sh000001'4 j& L( e3 x0 i- t R }" o
index_path = os.path.join(root_path, r'data\stock\basic_trading_data\index_data\%s.csv' % (index_stock_code))5 P( a2 j& u" q; Q- s
index_df = import_index_data(index_path)
$ v, [+ F1 C7 x, z* v3 ?! ^/ V3 t index_df = index_df[index_df['交易日期'] >= start_time]
- E7 x# y4 s3 u0 p+ u! } index_df['交易日'] = index_df['交易日期']( K+ A+ f8 |2 C
index_df.set_index("交易日期", inplace=True)% `7 [" x6 n5 D
index_quarter = index_df.resample(rule='1Q').agg({'交易日': 'last'})
+ B6 j& J: n1 h% T# } q_list = []; q. W$ \7 J' A# K
for index, row in index_quarter.iterrows():6 ^) N9 a W- i1 ]+ A$ {8 }
try:
6 r2 C8 U, N. U' v" v. G6 d7 e" i date = row['交易日'].strftime("%Y-%m-%d %H:%M:%S")
/ A% E" y5 c! t3 u/ V q_df = all_df[all_df['交易日'] == date] # 获取季度末数据
5 Z0 @+ j1 T0 I& Z6 L B! j0 [: j1 f- }; |0 g) l
min_val = 110
: y4 ^# x; V5 A max_val = 130
9 O7 ~, y3 T, @1 }( ~* l2 E6 q q_df = q_df[(q_df['转股价值'] >= min_val) & (q_df['转股价值'] <= max_val)]
2 V5 q: B0 h# C) p1 F
- k8 r7 \7 a( q- y) m* q$ Q, g( w' _ q_df['转股溢价率'] = q_df['转股溢价率'] / 100- F. P. c" H2 J1 P% @) K
# x轴是转股价值,y是转股溢价率0 q# h8 m |, k0 h, b2 A8 n
x = q_df['转股价值'].tolist()- O2 F! z: I- W9 x
y = q_df['转股溢价率'].tolist()
/ v$ ^- {2 L. A& { ?4 d# x7 m7 l/ g* ^/ f' `9 J* e& w& c
fit = np.polyfit(x, y, 2) # 拟合二元一次方程* O- k5 C% G8 K: N d5 M
p = np.poly1d(fit) # 得到多项式系数,按照阶数从高到低排列
3 L7 ?' l: N* G9 N! W # print(p) # 显示多项式
6 G: F% D5 S, I k = p.c[0] #得到系数
8 E3 U; V6 I0 B5 Z #各季度系数平均值9 q' n) G& z' {3 `; j3 i+ g6 E7 U
k_mean = (sum([x.get('k') for x in q_list]) + k) / (len(q_list) + 1) if q_list else k
4 s, ^: p, H* i! Z( j: d q_list.append({'quarter': date, 'k': k, 'k_m': k_mean})5 G$ g$ _% e8 f5 F. V
$ H$ k& O" n& `- v7 m& p
except:* j9 t/ Z. x( I4 R0 K8 C
continue! y% k" {9 v5 u3 k
return q_list+ K* _4 Y& p8 Z8 e
) \, K$ G. P9 W9 d L6 H$ _第二:高平价可转债估值指标的构建1 q. t8 A0 J9 k3 m+ K4 b \
高平价可转债的转股溢价率(修正版 H)= 转股溢价率+系数×(转股价值-120)8 Z( D8 k9 u8 a% B. U5 e# [
def cal_undervaluation(date, group, con_df, q_list):, ]5 p6 R& h/ s& @, o
"""
' @; Q3 h0 O* g8 G6 y! u# o 计算每天的因子数据
8 M. U* S$ v% i+ Q+ [1 ? """0 R+ R3 V: K$ R9 N
print(date)
c# L( X3 C. X$ z4 i" g I2 S # 根据时间,获取使用的系数, e4 Z8 x; G. h, Q2 F
k_m = 0
' Q2 @3 H0 t9 G9 V last_q = None
' v# N) i" P9 b* t+ x! s/ D last_k_m = 0' P7 t) [6 v& K6 B4 U1 g5 F
cur_date = pd.to_datetime(date)
6 r5 o0 _6 V! {8 W for q in q_list:; m% w p1 Z& z- _! c
cur_q = pd.to_datetime(q.get('quarter'))+ q$ V; w2 R( F2 u" Z; E
if last_q and cur_date > last_q and cur_date <= cur_q:& R a; b( b% s; r9 q3 v
k_m = last_k_m
" u# H6 _, P7 ~( Z, r3 ^ break
3 Y$ ?) a) p5 I+ V+ k9 b last_q = cur_q( \& o- R, J9 a
last_k_m = q.get('k_m')
/ Y- d/ M: \1 @) L7 R7 d1 g6 D( B2 @) D( @( F* U S' w& V! Z1 H) N7 d* m
tmp_df = group
/ i7 n5 ^' T. {( }+ @! K tmp_df = pd.merge(left=tmp_df, right=con_df[['到期日', '债券代码', '转债名称']], on='债券代码', how='left',sort=True, indicator=True)- I+ w4 a6 {1 O, H
! J! \6 s4 g- ?1 U: k4 X2 l tmp_df['转股溢价率'] = tmp_df['转股溢价率'] / 100: T: z4 T# `8 X1 H* h0 \# V
1 [3 u r& p* [1 {, H4 D: j+ R
#指标计算公式1 o0 b+ F/ g: J, t9 d
tmp_df['溢价率指标'] = tmp_df['转股溢价率'] + k_m * (tmp_df['转股价值'] - 120); e& G3 }, s; ]- F1 H
tmp_df.sort_values(by=['交易日期', '溢价率指标'], inplace=True)
5 c- A9 X: L& _ i return tmp_df构建策略因子后其它代码参考以前帖子,这里不再赘述& b0 A. L' G9 |! _: Q# i' F
10只,回测结果如下:+ w7 }3 V9 p9 \' ]; ? }
& R7 r% A, n) h8 m, B' o- \
3 S1 ^5 @1 ^8 g# B' E) ^- s9 {
3 C1 F1 Y0 j w1 }, \ * Z9 j4 K, V4 E: b) P) s; e; {, \
三种高性价比轮动策略
; x. j( z2 q0 @8 N% J
7 Q; w4 f) a$ Q3 P* F# ?2 L/ m可转债的转股溢价率越低,正股上涨时,可转债价格上涨的幅度越大,进攻性越强。可转债价格越低,往往纯债溢价率越低,正股下跌时,可转债价格下跌的幅度越小,防御性越强" y( S$ t2 D. p' s: N
我们根据价格、转股溢价率20%,50%,80%的分位值构建连线后,来构建修复后的价格,以此为依托来构建可转债轮动策略8 n. Y8 n8 ?9 `$ k7 x
研报回测结果
; C1 L1 ]$ r7 [6 c( m
/ D7 P: ?/ Q8 Y . E! \0 U6 K- Z9 ?& f7 }
结论:高价段高性价比轮动策略的收益明显高出低、中价段高性价比轮动策略,那么我们就来实现这个高价段高性价比轮动策略
* F6 s& ^( k) X7 D构建原理
6 k3 H9 C8 W- |* z2 E; P0 d* ~( a! J; B2 k, k% a
' d! Y$ h1 _, k![](http://pic4.zhimg.com/v2-166f435e67d6da92c042616b6992e073_r.jpg)
& ^8 l; t, s% ^# o; D/ H# v5 d第一:构建AD,BD,BE三条直线: A; S& ~# L) R
可转债价格与转股溢价率的分布图上的四个关键点为:A(价格为 20%分位值,转股溢价率为 80%分位值)、 B(价格为 20%分位值,转股溢价率为 50%分位值)、D(价格为 50%分位值,转股溢价率为 20%分位值)、E(价格为 80%分位值,转股溢价率为20%分位值)。三个关键直线为:经过 A 和 D 的直线 AD(斜率为 KAD)、经过 B 和 D 的直线 BD(斜率为 KBD)、经过 B 和 E 的直线 BE(斜率为 KBE)。
8 f+ [3 H5 `7 o, U认为价格低更为重要的投资者,使用AD直线作为低价段;对价格和转股溢价率的重视程度相近的投资者,使用BD直线作为中价段; 对价格和转股溢价率的重视程度相近的投资者,使用BE直线作为高价段;( i# W K ` o7 z! w
构建代码如下:
" E& i. a; C6 C' G: |def my_plt_percentile():" \) e. M D) e: P4 p
file_path = '''可转债数据.csv'''# N' V7 U' M2 \; c6 R
df = pd.read_csv(file_path, encoding='gbk')( c* E: g, k5 w$ ^( M
2 M6 A! x- s. K/ D9 U # 溢价率数据转化# ` X5 i1 s9 p. |2 Y
df['premium_rt'] = df['premium_rt'].apply(lambda x: pd.to_numeric(str(x).replace('%', '')))% |2 \3 H4 D2 D9 h% N% V. F
df = df[(df['price'] <= 200)]
2 G( a% u W; r0 X df = df[(df['premium_rt'] <= 60)]
: _+ N) u/ P' W- n+ E& @4 H x = df['price'].tolist()# Y9 n( f9 O D& v
x.sort()
0 Y, b/ G8 Q' F7 ?$ h; K2 L { x_max = max(x)7 k0 U) O; ~9 o( l. Y0 C" V
x_min = min(x)
8 ]' \6 j) g1 J$ W i2 v price_80 = np.percentile(np.array(([x])), 80) # 80%分位数
6 j/ [5 Y7 a5 w r% d/ n, t( x price_50 = np.percentile(np.array(([x])), 50) # 50%分位数
% q0 d4 a7 `2 [) k" w8 h: F price_20 = np.percentile(np.array(([x])), 20) # 20%分位数
6 U* {8 X/ I+ I6 j$ Y# \) D6 j: I: z+ z) `0 U
y = df['premium_rt'].tolist()
' B5 v/ e, A7 R# j- j+ t- E7 i y.sort()
6 H U b; H. h/ G. V' D1 ` _ y_max = max(y); V O0 E1 C& d# _- P
y_min = min(y)
4 g( d8 H. Z' f0 G premium_80 = np.percentile(np.array(([y])), 80) # 80%分位数
6 n( A8 P$ ]8 ]5 w, O premium_50 = np.percentile(np.array(([y])), 50) # 50%分位数* A, f8 P0 P7 z% y! ?
premium_20 = np.percentile(np.array(([y])), 20) # 20%分位数 V3 _# s1 }& N9 u
+ g+ O1 U* c w: I
* D/ m, E( o: M4 `& H; ?; n # 点坐标赋值
9 |4 ^9 H Z2 x' K) p7 K0 c) X5 }3 F/ _ a_cor = (price_20, premium_80)3 G4 T Z8 w" T; _! y
b_cor = (price_20, premium_50)
$ h: F% z: H- V `% x4 p c_cor = (price_20, premium_20)3 v- E4 T/ X# g9 j6 Z# G% Q3 p
d_cor = (price_50, premium_20)# w3 ^. e: X" L
e_cor = (price_80, premium_20)
3 H+ V f6 _; q; o$ {. o
( h* f- @) Q) E- O1 a5 H df['高阶段距离差值'] = df.apply(lambda row: cal_dis_test(row, b_cor, e_cor), axis=1) l( F% Z5 s7 M/ t/ {0 x( U9 T
df.sort_values(by=['高阶段距离差值'], inplace=True, ascending=False)
% `4 C X( a9 v- J8 B& M pass' K1 A. P. F7 f# |2 @5 A- r0 B
# #AD、BD、BE斜率计算
f$ [; R3 ]7 e k_ad = (a_cor[1] - d_cor[1]) / (a_cor[0] - d_cor[0])
3 b* m6 a4 ^2 c( S: p# d$ \ k_bd = (b_cor[1] - d_cor[1]) / (b_cor[0] - d_cor[0])( L, C: }- b4 E- G$ q6 q. X
k_be = (b_cor[1] - e_cor[1]) / (b_cor[0] - e_cor[0])
3 X& c2 g, L6 @
3 Q3 g$ Y4 C( \) M print("ad:%s,bd:%s,be:%s" % (k_ad, k_bd, k_be))
1 Z9 K2 t+ h& m9 x" D& S4 {
5 l. A0 m) h8 @ # 绘图部分1 W' k k# h2 @: @3 i7 w
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
) v; k0 c+ C- N9 `1 Q' `; X# D, B plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号1 D, }; U7 u4 i8 _$ v
plt.plot(df['price'].tolist(), df['premium_rt'].tolist(), '*', label='散点')
/ n' X+ Y1 o. e/ o& w; K # 溢价率分位线4 Z6 {' Y I4 V7 f1 `; c d
plt.plot([x_min, x_max], [premium_20, premium_20], c='gray', linestyle='--')& R. i9 \( t4 q
plt.plot([x_min, x_max], [premium_50, premium_50], c='gray', linestyle='--')
9 `3 e) R2 Y" b2 J' v plt.plot([x_min, x_max], [premium_80, premium_80], c='gray', linestyle='--')
" h1 m: Y3 A! t Q+ ?
. }; @% i# o) }) g) Y # 价格分位线1 I" d& b/ t. x9 z
plt.plot([price_20, price_20], [y_min, y_max], c='gray', linestyle='--')
( x$ }; I" ?& a* e* g2 W plt.plot([price_50, price_50], [y_min, y_max], c='gray', linestyle='--') U z$ h8 z' ^" I9 V6 D; d
plt.plot([price_80, price_80], [y_min, y_max], c='gray', linestyle='--')
; u3 J: K0 ^& A" q' X) E: [" T
) [- d, l& T, n# {* f # AD连线
) J' j9 X, u: {) G1 u plt.plot(
; {8 `* c, e& q9 n" Y [get_linear_equation_other_val(a_cor, d_cor, y=y_min), get_linear_equation_other_val(a_cor, d_cor, y=y_max)],
& {( \% C) A$ u [y_min, y_max], c='r', linestyle='-', label='低价段性价比')# n+ F) c: G; N; r: U
# BD连线
9 A" b- w3 W+ L+ E% c if get_linear_equation_other_val(b_cor, d_cor, y=y_max) < x_min:
. P/ b. R- z. _ plt.plot([get_linear_equation_other_val(b_cor, d_cor, y=y_min), x_min],
1 ~0 I4 }1 G; p& K$ L# v [y_min, get_linear_equation_other_val(b_cor, d_cor, x=x_min)], c='b', linestyle='-', label='中价段性价比')
/ [# e1 l& i1 G x$ t7 w& _ else:
( k, S5 q& F& p plt.plot([get_linear_equation_other_val(b_cor, d_cor, y=y_min),
! ~0 i3 ?; r! G" I$ j4 _ g get_linear_equation_other_val(b_cor, d_cor, y=y_max)],& }) n5 \ L8 K7 L! ~
[y_min, y_max], c='b', linestyle='-', label='中价段性价比')
8 x2 n) }& g# e # BE连线
# p. q1 ^- ^1 U if get_linear_equation_other_val(b_cor, e_cor, y=y_max) < x_min:) U. L1 h3 n9 w* O# b
plt.plot([get_linear_equation_other_val(b_cor, e_cor, y=y_min), x_min],: a' I W" d \. L
[y_min, get_linear_equation_other_val(b_cor, e_cor, x=x_min)], c='g', linestyle='-', label='高价段性价比')- a! L6 p' w. \ y) @; b6 c6 g
else:
+ W# y2 h+ p' k( h3 O( D% t plt.plot([get_linear_equation_other_val(b_cor, e_cor, y=y_min),- l; B$ M+ g+ f
get_linear_equation_other_val(b_cor, e_cor, y=y_max)],
/ B# ]' y6 q5 y: ^2 A [y_min, y_max], c='g', linestyle='-', label='高价段性价比')
$ Q- E/ P/ a) {& q. n1 k$ f
* ^% g; X! L2 }6 a4 W2 m plt.xlabel('价格(元)')
( r _' U) r! B, r: N0 |0 E plt.ylabel('转股溢价率')
; m$ n2 W6 E7 s* E# T; A, I plt.legend(loc=1) # 指定legend在图中的位置,类似象限的位置 y `( e7 ~' Z% m! i
plt.title('存量可转债价格与转股溢价率分布')' x3 o* q& [! N, E' j
plt.show()这样我们也构建和研报中类似的三条线,我们依托这三条线中的高价段BE来构建因子% K% W3 M& R, z/ L
' a- ^+ L% x+ b/ g* V& j6 k1 ^
$ m* O# h) W3 N) p S* W2 p* k: i, U* j第二:高价段高性价比可转债估值指标的构建( a1 K _/ p" e$ a# v( h4 J* s
性价比指标 BE=价格 – 1/KBE×转股溢价率! r/ |& o! Z/ J$ @4 b5 I
def cal_distance(date, group, con_df):
- t4 T4 @; `6 A5 Q( Y; N print(date)
, t: N4 ^: }+ F' L if pd.to_datetime(date) == pd.to_datetime('2020-07-31'):
: k: s7 _5 @! w: g" M `2 v a = 1
7 `0 H3 n+ D4 n5 D$ E* y( {, e tmp_df = group# m; }% n- V8 g$ N! X' F/ J5 y' x
tmp_df = pd.merge(left=tmp_df, right=con_df[['到期日', '债券代码', '转债名称']], on='债券代码', how='left',
: I/ Y+ k& h+ p. a sort=True, indicator=True)
# t; @& g* X) \6 @' [$ t& j4 U) y5 y/ r8 r1 |! f$ f5 o1 B5 F0 w
# 溢价率数据转化
6 ^, ^9 q' o5 N7 v" Y x = tmp_df['close'].tolist()
9 q+ D' ?* X5 n+ H8 i x.sort()* Z$ G; f2 P/ j9 A/ V) h
price_80 = np.percentile(np.array(([x])), 80) # 80%分位数
# F W3 _1 b: a1 G% a/ O( q price_50 = np.percentile(np.array(([x])), 50) # 50%分位数
0 w! |* h a" T' q price_20 = np.percentile(np.array(([x])), 20) # 20%分位数+ F% `2 n. X$ \6 ]0 t y d3 A
, q3 H! Z; C! B& D' t9 e
tmp_df['转股溢价率'] = tmp_df['转股溢价率'] / 100
( f) j9 a# q0 B1 ]0 ~ A6 I8 \ y = tmp_df['转股溢价率'].tolist()
% s8 R% ~3 s9 A) P+ R% G9 Y# H y.sort()
9 |$ l0 A7 Q0 l: { Y& P premium_80 = np.percentile(np.array(([y])), 80) # 80%分位数
/ N- t: y- {3 w5 s' Y premium_50 = np.percentile(np.array(([y])), 50) # 50%分位数
+ [% l' {. T4 h5 {. @8 ] B premium_20 = np.percentile(np.array(([y])), 20) # 20%分位数
* w7 s1 V, B- X' v: ~2 y. f" S
3 b* o( i& ` w; v8 u; T# s # 点坐标赋值
: Z1 ]3 {* P4 c3 X6 M0 f* [* a a_cor = (price_20, premium_80)! P7 [) y% c9 r7 O# G
b_cor = (price_20, premium_50)
9 [! [: {$ L: u, S) R1 a! s c_cor = (price_20, premium_20)5 K# w" U1 a1 z' r. G5 M
d_cor = (price_50, premium_20)8 L6 ?$ ]9 m% L
e_cor = (price_80, premium_20)
2 s! [( s! A! d+ R& H3 ^ S9 Z
2 F) G5 j9 L3 @0 _1 J6 P5 r k = (b_cor[1] - e_cor[1]) / (b_cor[0] - e_cor[0])9 @; D) V6 B- s+ a/ U: T! K
#依托BE构建指标
* n F9 D' Y# E) u' o1 Z tmp_df['性价比指标'] = tmp_df.apply(lambda row: cal_price_effective(row, b_cor, e_cor), axis=1)
2 W! b7 \1 {4 Z% L+ ~6 J e7 ^, F& g* h0 E7 a) F- q$ I
tmp_df.sort_values(by=['交易日期', '性价比指标'], inplace=True)
. Z9 O; D3 T. N/ Q # tmp_df['偏移值_排名'] = df.groupby('交易日期')['偏移值'].rank(method="first")! ]( X: @) ~0 I; v) c1 l
return tmp_df构建策略因子后其它代码参考以前帖子,这里不再赘述: u) u! k% ^1 C* N/ N7 N, z+ k, q* U
选取10只,回测结果如下: P( ^! _6 Q& X# C; U
2 W! C4 ^' q1 N' g
; |/ u) G# c5 n' N" y( M. v4 d
6 j/ T& s( t- d0 c
- X% R6 s% z0 z8 B2 h2 G结束语+ p V' n, F6 p7 w) u! d2 l: Z
2 ~% s7 \4 N5 J7 w- m/ H7 c& U
这两个回测不错的轮动策略,都属于包含高价的策略,我之前只关注一些低价标的,回测效果没有这么好,看来还是高价格的相对进攻性比较强,后期计划分出一部分资金参与一下;有对此策略感兴趣的朋友欢迎评论或私信讨论;
" q( X9 U- P. f& `+ u如果本篇对你有所帮助,请动动手指点个赞表示支持,感谢
$ u4 M$ n' b2 z$ |- s" o9 ~) y附件:
0 i! M% D! t$ t% \; y- m# d# D7 e8 W' ]& O+ t
|