可转债轮动着重低转股溢价率的策略占优收益爆炸【python数字货币量化_21精华帖_策略第35篇】

[复制链接]
查看8365 | 回复0 | 2023-8-6 04:09:17 | 显示全部楼层 |阅读模式
引言" m! W3 r/ i+ U6 I* H6 N8 Q

0 D( ~6 G: u2 i! Z自己平时也在研究一些可转债策略,也会关注一些可转债的研报,近期阅读与研究了光大证券2020年8月发布的一篇研报《可转债轮动策略研究系列之一:着重低转股溢价率的策略占优》;这篇研报的内容还是很不错的,研究转债的小伙伴推荐阅读;今天我们来研究学习一下本篇研报,研报中介绍了三种低价类轮动策略、三种低估值轮动策略、三种高性价比轮动策略一共九种策略,我挑选了其中2个收益高的策略来进行复现7 n- _" N8 L0 F/ X+ L
三种低价类轮动策略( C7 J; U' |" d7 U
# D: `8 b! {9 g2 z, {6 ?
回测设置:
4 I1 q+ [% R# o) M9 S9 w% s. ?1. 每月调仓 1 次,调仓时间为月末最后一个交易日,买入价为月末最后一个交易日收盘价4 j5 w5 C, p& T- I! W. f/ P: j
2. 组合选取择券指标排序在前的 10 只个券
, K/ I% R0 ~* w/ y4 L% J2 f( k4 j/ D3. 回测时段为 2018 年以来,主要原因为 2018 年 1 月二级市场存量可转债数量首次突破 40 个,之前可选择的标的数量偏少
/ v3 P& ?. v/ c( B4. 标的选择范围为债券余额大于 2 亿元(含),初始评级高于 AA-(含). z2 f+ H  V% `4 }# E
① 低价轮动策略:每期选择价格最低的标的
  P$ O. W, ^: C& \+ L! r9 s2 p② 高到期收益率轮动策略:每期选择到期收益率最高的标的
" q5 s, |" o  R$ y8 ?. n9 a③ 低纯债溢价率轮动策略:每期选择到纯债溢价率最低的标的
* G+ i! k/ k# Y3 w( V- b. V8 @4 X; O) }
可转债轮动着重低转股溢价率的策略占优收益爆炸【python数字货币量化_21精华帖_策略第35篇】-1.jpg 1 N* o5 X0 K. Q
回测结论:低价格轮动策略、 高 YTM 轮动策略、低纯债溢价率轮动策略在 2018 年 1 月 1 日至 2020 年 8 月 17 日的收益率(年化)分别为 13.15%、11.08%和 9.62%,与同期中证转债指数的年化涨幅(11.45%)差异不大* |4 e5 `3 n" R$ C/ ]
虽然这几个策略收益不高,但是对于价格能够低于100元面值或者到期收益率较高的标的买入,我们持有者拿着不慌,能睡好觉! K5 O3 x) `2 M5 W4 _' s
三种低估值轮动策略& E& M8 t& l# W
# @& a8 a& o# q
用转股价值(或称为平价)进行分类,这种方法本质上是弱化纯债价值的差异
# x# w" M9 i( `4 g; d- n0 Z; \将主要的可转债分为低平价(转股价值位于 70 元至 90 元之间)、中平价(转股价值位于90 元至 110 元之间)和高平价可转债(转股价值位于 110 元至 130 元之间)。
: ~2 ?. U, {+ j% I! l; O5 D2 x7 U对于低平价、中平价、高平价三类可转债,转股溢价率是最常见和直观的可转债估值指标,但它又存在较大的缺陷,那就是单纯的依靠溢价率来作为转债股指是不科学的;因为转股溢价率与转股价值具有一定的相关性,我们可以来拟合其相关性,来构建修复后的溢价率,以此为依托来构建可转债轮动策略
: G  M& ?2 @; `+ |& @) F$ r研报回测结论
& g; f6 E% m; d) F1 k/ u7 V) ^4 p* ?2 u/ ^$ [+ k$ P
可转债轮动着重低转股溢价率的策略占优收益爆炸【python数字货币量化_21精华帖_策略第35篇】-2.jpg ! s/ j/ y" e5 P+ S" t. I# V5 x
结论:高平价低估值轮动策略的收益明显高出低、中平价轮动策略,那么我们就来实现这个高平价低估值轮动策略$ d$ T: `# ^9 v; x  e6 c% o9 F" e
构建原理
& O( R8 W' o, S. j
0 \% V, V& {) Q6 U0 ^4 _
, F; V2 E' t" T 可转债轮动着重低转股溢价率的策略占优收益爆炸【python数字货币量化_21精华帖_策略第35篇】-3.jpg
! H. @1 l& U, v2 E4 e$ l1 F3 w第一:构建高平价可转债转股溢价率与转股价值的相关系数
, {$ C" n3 ]( ~0 P4 J根据研报,我们根据选择每个季度末转股价值在110元到130元之间的转债数据(转股价值和转股溢价率)分别拟合构建每个季度的转股溢价率与转股价值的相关系数;然后计算季度系数的平均值
4 Z' u5 o' q) n; w2 E# Y) Y代码如下:: t% ?$ P* Z' C" M7 L
def build_quarter_data(start_time):& }) [0 c  E" ]! e
    """- K3 g3 i& b( j6 Y
    构建季度高平价可转债转股溢价率与转股价值的相关系数
7 o. S4 v) i: r( _) A    """
/ H+ C# D; @" U; J    file_list = []
  O& y2 F, f6 ^# A: y4 ]; C    path = os.path.join(root_path, r'data\stock\basic_trading_data\convertible'), D. Q! B5 [4 s
2 E; ]/ \2 `; {
    # 系统自带函数os.walk,用于遍历文件夹中的所有文件% b5 w9 e& r1 {( Y) o
    for root, dirs, files in os.walk(path):
; J" h: j: |# o  {2 Y6 Y  y9 \        if files:  # 当files不为空的时候; o( {" T/ g. m( h! f/ d
            for f in files:" h' x9 w9 T( ?; F% I. i
                if '.csv' in f:
5 X7 Z2 v- s- x/ f                    file_list.append(os.path.join(path, f))
/ G3 {: G5 O7 v1 q8 |    # 并行/ b# {! C4 v7 s
    with Pool(processes=8) as pool:* r/ A5 L" h" g2 v( y
        all_df = pool.map(cal_con_quarter, file_list)
' e4 Z' W8 R. j6 s- M# E    all_df = pd.concat(all_df, ignore_index=True)* x0 e/ V" Q( w9 K8 p8 J" C) f
# u$ d+ s# H- g6 `5 q$ n
    # 导入上证指数,保证指数数据和股票数据在同一天结束,不然会出现问题。
; \! l3 `0 N% `    index_stock_code = 'sh000001'# ~/ F& z0 O6 F( d2 B
    index_path = os.path.join(root_path, r'data\stock\basic_trading_data\index_data\%s.csv' % (index_stock_code))
& v6 x  X8 R. m, D    index_df = import_index_data(index_path)2 ]9 B* }8 V: M# g
    index_df = index_df[index_df['交易日期'] >= start_time]
2 O, x  G  \& k& V9 U- }* M# I5 o    index_df['交易日'] = index_df['交易日期']
! W  t' T/ v' w* H' a    index_df.set_index("交易日期", inplace=True)4 X8 `& F' B: `! Y
    index_quarter = index_df.resample(rule='1Q').agg({'交易日': 'last'})
9 U, R$ A5 p$ e: s3 v& N, A& x    q_list = []
, [% X2 \; A" G( _0 k* k    for index, row in index_quarter.iterrows():
2 l9 s. X" m/ g2 m        try:
8 B3 V, O9 {! l  |. o; P. Q8 s            date = row['交易日'].strftime("%Y-%m-%d %H:%M:%S")
' ~/ Q3 x- G0 C0 m( u            q_df = all_df[all_df['交易日'] == date] # 获取季度末数据, _; h4 A+ @$ r) w! p2 u: r: }

! ?+ _1 E. @; M' l' u% m& }            min_val = 110
7 x  n1 d- _1 g/ o1 P5 E8 Y' G            max_val = 130% d* @7 a% z. H7 l6 j7 `, q
            q_df = q_df[(q_df[&#39;转股价值&#39;] >= min_val) & (q_df[&#39;转股价值&#39;] <= max_val)]* p+ a# d0 r% M+ \. w0 M( S6 ~

5 n4 @! W' w$ e% U5 @. i) e            q_df[&#39;转股溢价率&#39;] = q_df[&#39;转股溢价率&#39;] / 1008 H6 C. R, ]6 L8 u2 W7 K% I" t
            # x轴是转股价值,y是转股溢价率
* `% y4 y' y8 u2 s1 W            x = q_df[&#39;转股价值&#39;].tolist(); I! t- e& X' m! t. q; P$ ^: [
            y = q_df[&#39;转股溢价率&#39;].tolist()
8 Q- F. a/ H* Y# M  k, E4 d: o, B. v9 o% j
            fit = np.polyfit(x, y, 2)  # 拟合二元一次方程
8 ~+ _7 z. Z6 P- t! X  S            p = np.poly1d(fit)  # 得到多项式系数,按照阶数从高到低排列3 e/ e, I* j% ~3 U- J0 E/ H( d# H
            # print(p)  # 显示多项式
( y- C  E$ y1 x* _            k = p.c[0] #得到系数  t% i: ~- g! p! @, V, y. v7 r9 k
            #各季度系数平均值
- B; K) }; b, d0 J            k_mean = (sum([x.get(&#39;k&#39;) for x in q_list]) + k) / (len(q_list) + 1) if q_list else k
% ~$ }; K5 p4 v/ ?4 I1 u4 \1 Q            q_list.append({&#39;quarter&#39;: date, &#39;k&#39;: k, &#39;k_m&#39;: k_mean})! W& A' Y" l/ M2 E6 J
            2 b5 H1 l) n7 s$ \0 u& B
        except:
' }$ r3 C: j% q9 w/ G. D            continue
: `% r! ]  L( b: {6 ^+ Yreturn q_list
* b) p/ V# v6 W, C( q0 W
$ t2 x7 M" J6 E. }/ x% T+ M第二:高平价可转债估值指标的构建
1 E0 w1 c( P( a6 L/ m1 f  X高平价可转债的转股溢价率(修正版 H)= 转股溢价率+系数×(转股价值-120)' R: I1 z' U5 t
def cal_undervaluation(date, group, con_df, q_list):
  a% O. L3 l$ z& X4 i# g  M3 I7 O) |! l( S   &#34;&#34;&#34;' ]3 N6 c! S% `) W; ^- ?
   计算每天的因子数据
: i& R# f3 Y: A, ]4 `# V   &#34;&#34;&#34;: M9 N) [9 S! ^; p# A# M
   print(date), `  }! C) t7 K' i: w
   # 根据时间,获取使用的系数1 }6 z' Q+ q% }6 v
   k_m = 0
) U0 ]$ i  i  w0 ~  ~8 E6 q- u* B4 C6 D   last_q = None0 [) Q. k, n+ t
   last_k_m = 0
2 e- O+ _% F+ g+ @" T& Z) R   cur_date = pd.to_datetime(date)9 T. X. N! `' N& }4 ]6 v8 V& N" J
   for q in q_list:
' s. c6 d. r2 s8 V% T" ~5 \       cur_q = pd.to_datetime(q.get(&#39;quarter&#39;))
5 g% J: d5 c! L+ H       if last_q and cur_date > last_q and cur_date <= cur_q:
: l/ y* t: @/ d: ~) S/ v  v           k_m = last_k_m* h0 k8 [+ u4 D. U$ |# ]
           break( M# W" x1 a- U' g, R
       last_q = cur_q
7 d$ w& W' ~% Y* H8 ~& ?. t       last_k_m = q.get(&#39;k_m&#39;)2 z/ U5 ?  r3 x- Q( q
9 k6 Q8 W) i! _0 n! L
   tmp_df = group, [. B  g" B7 ~: r/ P' T
   tmp_df = pd.merge(left=tmp_df, right=con_df[[&#39;到期日&#39;, &#39;债券代码&#39;, &#39;转债名称&#39;]], on=&#39;债券代码&#39;, how=&#39;left&#39;,sort=True, indicator=True)6 b! i1 r* }  [' z; z4 R
. Q# z* c. W3 K" q
   tmp_df[&#39;转股溢价率&#39;] = tmp_df[&#39;转股溢价率&#39;] / 100, z  J8 ]8 A: Y: V% t

2 h1 y# x. T$ e" j; X   #指标计算公式
" }3 j" a/ n0 U. v& x5 n8 U7 q6 q   tmp_df[&#39;溢价率指标&#39;] = tmp_df[&#39;转股溢价率&#39;] + k_m * (tmp_df[&#39;转股价值&#39;] - 120)8 M$ v0 N6 r' t- f# t) s3 S: v
   tmp_df.sort_values(by=[&#39;交易日期&#39;, &#39;溢价率指标&#39;], inplace=True)" l, P( O) k6 f1 |8 H8 l7 t" {
   return tmp_df构建策略因子后其它代码参考以前帖子,这里不再赘述
/ s! Y6 w2 j, `/ j10只,回测结果如下:
+ Y3 O8 w2 O- w# s% g8 B; x. U" W* H/ w7 a8 z$ ?, `- B5 _* i
可转债轮动着重低转股溢价率的策略占优收益爆炸【python数字货币量化_21精华帖_策略第35篇】-4.jpg : D) E; z8 g! J9 P8 p. M- o

' A5 h1 y  n1 U6 Y5 k" D
3 S3 _2 w/ H$ d% a0 K三种高性价比轮动策略
# q) m* v  D1 e0 k) t2 p9 V% C& g8 n7 C% N# i# ]% F7 P
可转债的转股溢价率越低,正股上涨时,可转债价格上涨的幅度越大,进攻性越强。可转债价格越低,往往纯债溢价率越低,正股下跌时,可转债价格下跌的幅度越小,防御性越强
- `4 r; K" G2 }7 m我们根据价格、转股溢价率20%,50%,80%的分位值构建连线后,来构建修复后的价格,以此为依托来构建可转债轮动策略1 a; @0 S% e# R$ P
研报回测结果  O1 O8 ^: V; L$ O+ n- s

$ Z2 V  @# w; t5 |* f
+ |, W; p$ W* K/ g: L# w结论:高价段高性价比轮动策略的收益明显高出低、中价段高性价比轮动策略,那么我们就来实现这个高价段高性价比轮动策略
$ C8 }+ l2 h! Q- g7 T4 N构建原理
' j$ _- }$ a8 Y+ \$ R
% l8 S6 [, k6 B2 p8 }1 R# I/ f, V9 q4 D' E3 R; E, l

+ A. {7 f% k8 d# J6 V第一:构建AD,BD,BE三条直线; F5 @! s( \) B% N# U
可转债价格与转股溢价率的分布图上的四个关键点为:A(价格为 20%分位值,转股溢价率为 80%分位值)、 B(价格为 20%分位值,转股溢价率为 50%分位值)、D(价格为 50%分位值,转股溢价率为 20%分位值)、E(价格为 80%分位值,转股溢价率为20%分位值)。三个关键直线为:经过 A 和 D 的直线 AD(斜率为 KAD)、经过 B 和 D 的直线 BD(斜率为 KBD)、经过 B 和 E 的直线 BE(斜率为 KBE)。5 ]3 l4 o! J# k. x! k7 s7 C
认为价格低更为重要的投资者,使用AD直线作为低价段;对价格和转股溢价率的重视程度相近的投资者,使用BD直线作为中价段; 对价格和转股溢价率的重视程度相近的投资者,使用BE直线作为高价段;
; H1 A) t0 K/ O5 [+ T" p' t构建代码如下:4 L3 d( U' X$ [% u; R( A
def my_plt_percentile():% x6 y$ K( [; o6 M
    file_path = &#39;&#39;&#39;可转债数据.csv&#39;&#39;&#39;
/ N# V- n' R3 O) O    df = pd.read_csv(file_path, encoding=&#39;gbk&#39;)
7 L6 g* h. E6 x" ?
  y3 |$ w" n* |" t9 m2 j5 P- r    # 溢价率数据转化4 @9 R1 U# l! G, G7 U
    df[&#39;premium_rt&#39;] = df[&#39;premium_rt&#39;].apply(lambda x: pd.to_numeric(str(x).replace(&#39;%&#39;, &#39;&#39;)))0 W$ h: d6 [" |% K
    df = df[(df[&#39;price&#39;] <= 200)]
! t* s1 |; }% V8 ^1 s    df = df[(df[&#39;premium_rt&#39;] <= 60)]/ Z0 _+ Y2 a1 y- u
    x = df[&#39;price&#39;].tolist()
5 l# \4 l; f+ S8 X    x.sort()$ X4 K  W6 Q$ y$ W- o  g& ?2 k9 N* A
    x_max = max(x)
) y, r; a* G# `+ H    x_min = min(x)' @* m, R& P8 E
    price_80 = np.percentile(np.array(([x])), 80)  # 80%分位数
) P5 [+ Z# H; c7 J0 z    price_50 = np.percentile(np.array(([x])), 50)  # 50%分位数
' Q2 }) i& c! T" ^    price_20 = np.percentile(np.array(([x])), 20)  # 20%分位数/ ~  u2 B# m: L
# C$ r1 k/ ]$ E9 [; E2 S; L
    y = df[&#39;premium_rt&#39;].tolist()* r- R7 M: u+ F5 U
    y.sort()- }, \4 ~* n" ^
    y_max = max(y): F% y8 F* Q) Z/ _; W
    y_min = min(y)  p' e5 O8 l1 r$ S' V. K/ y
    premium_80 = np.percentile(np.array(([y])), 80)  # 80%分位数; D6 |6 G  s4 l; _$ ~
    premium_50 = np.percentile(np.array(([y])), 50)  # 50%分位数
5 x1 r  K5 A8 ?: a' ^& B% d    premium_20 = np.percentile(np.array(([y])), 20)  # 20%分位数
0 V5 d% }; a. w* f( U1 C
; c( S$ R. n, f& a4 n, q+ N+ c; S* [  D. ^/ V, e
    # 点坐标赋值
* m! o0 N- G2 |0 \( C8 }. Z5 T4 A    a_cor = (price_20, premium_80)2 [7 N$ y* f8 H( L2 `4 s
    b_cor = (price_20, premium_50)
0 I6 g$ x/ H$ {    c_cor = (price_20, premium_20)) u# ]- V6 o- n# F- S
    d_cor = (price_50, premium_20)
+ e* j: [( s3 g/ J    e_cor = (price_80, premium_20)
9 F& B. b2 Y  B0 Y
5 _' R0 Q$ O( o9 j    df[&#39;高阶段距离差值&#39;] = df.apply(lambda row: cal_dis_test(row, b_cor, e_cor), axis=1)) V+ f! B6 A1 `/ {/ A' \' R
    df.sort_values(by=[&#39;高阶段距离差值&#39;], inplace=True, ascending=False)
* n0 ^4 d! e" }+ l& T    pass4 ]4 ?( {& @( `$ \5 I
    # #AD、BD、BE斜率计算, `5 l* Q& {5 m( H$ }- [* x1 @4 l
    k_ad = (a_cor[1] - d_cor[1]) / (a_cor[0] - d_cor[0])5 f. ^- c0 }! t. X) P4 Q- E
    k_bd = (b_cor[1] - d_cor[1]) / (b_cor[0] - d_cor[0])
: ~2 s0 [+ ~* C. f4 @! C    k_be = (b_cor[1] - e_cor[1]) / (b_cor[0] - e_cor[0])" P1 L/ H7 m. W0 D% W3 c4 b
2 g& _6 M( Q2 B4 X$ _6 C7 j
    print(&#34;ad:%s,bd:%s,be:%s&#34; % (k_ad, k_bd, k_be))
9 T) K6 U( @$ H6 Y& T- @# Y& v# y3 y! m8 F8 X7 B: {/ |% F
    # 绘图部分; Q! @9 e8 @& W; j
    plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;]  # 用来正常显示中文标签- S- H. Z' q% H
    plt.rcParams[&#39;axes.unicode_minus&#39;] = False  # 用来正常显示负号
5 G( h( ^3 e6 \4 L* `: l' R    plt.plot(df[&#39;price&#39;].tolist(), df[&#39;premium_rt&#39;].tolist(), &#39;*&#39;, label=&#39;散点&#39;)2 @2 `8 n2 o8 Z
    # 溢价率分位线
! U4 \7 Q* Z5 a! {! o$ t1 p& v) p    plt.plot([x_min, x_max], [premium_20, premium_20], c=&#39;gray&#39;, linestyle=&#39;--&#39;)
4 Z& G! J; _+ v" m! E    plt.plot([x_min, x_max], [premium_50, premium_50], c=&#39;gray&#39;, linestyle=&#39;--&#39;)
% N8 T# g8 T3 n: N/ Y% X6 k3 n    plt.plot([x_min, x_max], [premium_80, premium_80], c=&#39;gray&#39;, linestyle=&#39;--&#39;)
7 u. D; a, C+ a' [3 f% x! r3 Q  @2 w7 n  Q  [( a, @2 ?
    # 价格分位线2 Q) c( N9 s$ X( [( `( a1 w( f
    plt.plot([price_20, price_20], [y_min, y_max], c=&#39;gray&#39;, linestyle=&#39;--&#39;)
/ y' Z+ l( L* H6 S% I    plt.plot([price_50, price_50], [y_min, y_max], c=&#39;gray&#39;, linestyle=&#39;--&#39;)
9 Q* L. u! W% G  k/ [) y, y    plt.plot([price_80, price_80], [y_min, y_max], c=&#39;gray&#39;, linestyle=&#39;--&#39;)! ]- Z/ N& w4 F6 H

/ W% l$ n4 y3 U/ X( B0 |& v    #  AD连线: _; F" x: r8 j+ [
    plt.plot(& k7 M% G: }6 a7 ^: F- f
        [get_linear_equation_other_val(a_cor, d_cor, y=y_min), get_linear_equation_other_val(a_cor, d_cor, y=y_max)],
1 b0 y- ]1 D7 b6 d5 W        [y_min, y_max], c=&#39;r&#39;, linestyle=&#39;-&#39;, label=&#39;低价段性价比&#39;)
+ }; G4 C% N( n8 e# E    #  BD连线
7 R6 y- U( l; V- `8 y% d) t    if get_linear_equation_other_val(b_cor, d_cor, y=y_max) < x_min:; J' q6 P) Q2 Y1 \+ S; f& k) q
        plt.plot([get_linear_equation_other_val(b_cor, d_cor, y=y_min), x_min],
- b0 `# m# o$ \( f1 X2 e! \                 [y_min, get_linear_equation_other_val(b_cor, d_cor, x=x_min)], c=&#39;b&#39;, linestyle=&#39;-&#39;, label=&#39;中价段性价比&#39;)
8 z, B$ C5 I: F* K, D    else:
0 f) p8 G1 _8 h. e7 e' O( J/ F5 `: l        plt.plot([get_linear_equation_other_val(b_cor, d_cor, y=y_min),
$ n  P3 E% r, H# I' T& U9 _                  get_linear_equation_other_val(b_cor, d_cor, y=y_max)]," y& Q2 @2 i2 J: [; n6 p' j# K9 h( W5 D
                 [y_min, y_max], c=&#39;b&#39;, linestyle=&#39;-&#39;, label=&#39;中价段性价比&#39;)) a+ U! Z3 y- M
    #  BE连线2 l3 K0 k; l' G! }
    if get_linear_equation_other_val(b_cor, e_cor, y=y_max) < x_min:. v5 r) u) t: x, l, I, i
        plt.plot([get_linear_equation_other_val(b_cor, e_cor, y=y_min), x_min],' w$ q5 e5 N0 j: z/ l+ Q9 l; D$ |
                 [y_min, get_linear_equation_other_val(b_cor, e_cor, x=x_min)], c=&#39;g&#39;, linestyle=&#39;-&#39;, label=&#39;高价段性价比&#39;)
; j7 T$ u5 k% v( j( b( U    else:
& m- c1 w& ^/ k        plt.plot([get_linear_equation_other_val(b_cor, e_cor, y=y_min),% o* W  D/ W2 I% h( |% Z) w& q) i
                  get_linear_equation_other_val(b_cor, e_cor, y=y_max)],
& N' X( }+ q2 n' K9 f% {                 [y_min, y_max], c=&#39;g&#39;, linestyle=&#39;-&#39;, label=&#39;高价段性价比&#39;)' w# }8 J/ T; b8 v

' {- C* G- j6 K- ]    plt.xlabel(&#39;价格(元)&#39;)# u& _2 @, G- m/ I  c2 {) P
    plt.ylabel(&#39;转股溢价率&#39;)8 Y) V/ h% P* K: r
    plt.legend(loc=1)  # 指定legend在图中的位置,类似象限的位置3 x/ B% I) @' E4 x% z: U
    plt.title(&#39;存量可转债价格与转股溢价率分布&#39;)' }# p8 J- A! G5 O2 b# g4 e
    plt.show()这样我们也构建和研报中类似的三条线,我们依托这三条线中的高价段BE来构建因子
) h- z; X. Z, R8 \8 O3 h: ?
+ r& f" X$ \* M" @6 Y0 B 可转债轮动着重低转股溢价率的策略占优收益爆炸【python数字货币量化_21精华帖_策略第35篇】-8.jpg 5 C- Z3 V( |% t
第二:高价段高性价比可转债估值指标的构建
- t% Q. `6 P$ [! a; G+ H+ H0 @) ?性价比指标 BE=价格 – 1/KBE×转股溢价率& V/ k6 J( z, V6 S, \
def cal_distance(date, group, con_df):4 O8 r/ Z4 q. S4 k
    print(date)! W, S7 C7 x; H$ N4 U3 M8 G
    if pd.to_datetime(date) == pd.to_datetime(&#39;2020-07-31&#39;):
+ v' c; v6 S: y        a = 1
8 u0 q3 b) x  a# M5 `    tmp_df = group) t0 l, n4 [) _" e8 v6 ~
    tmp_df = pd.merge(left=tmp_df, right=con_df[[&#39;到期日&#39;, &#39;债券代码&#39;, &#39;转债名称&#39;]], on=&#39;债券代码&#39;, how=&#39;left&#39;,/ b! I, X! t0 E- a
                      sort=True, indicator=True)
- O$ K7 M) Y+ u7 W3 e9 O4 @/ f  }. G/ B# N4 W4 ^6 D
    # 溢价率数据转化
, a; ~' b( e( f, \  L0 ]    x = tmp_df[&#39;close&#39;].tolist()
& |5 t5 b3 z  Q# \$ ?, }    x.sort()& A- d9 Y8 m3 ^% r
    price_80 = np.percentile(np.array(([x])), 80)  # 80%分位数
: E! c+ i7 p9 I6 C3 ?% h. j    price_50 = np.percentile(np.array(([x])), 50)  # 50%分位数
  q( k1 c' s. n$ [    price_20 = np.percentile(np.array(([x])), 20)  # 20%分位数) N4 r. B+ ?! W
4 c  l( b/ v8 O5 }1 c' c
    tmp_df[&#39;转股溢价率&#39;] = tmp_df[&#39;转股溢价率&#39;] / 100% ]6 W7 |6 R; U$ e5 ~7 ~
    y = tmp_df[&#39;转股溢价率&#39;].tolist()
  a8 O. i9 t- I( x3 ?1 @    y.sort()
8 W9 D+ [# E* K- _    premium_80 = np.percentile(np.array(([y])), 80)  # 80%分位数' u9 |3 f1 v4 x* q, q* {6 g
    premium_50 = np.percentile(np.array(([y])), 50)  # 50%分位数" R. [6 Z/ h( \8 e' Q) x
    premium_20 = np.percentile(np.array(([y])), 20)  # 20%分位数
& M; _# d3 r$ |/ F# _: M
9 W2 c. ?* K7 e( u6 i4 ^    # 点坐标赋值4 Y9 h+ t% i0 X- Z& e6 w$ {: f: o
    a_cor = (price_20, premium_80)
8 ]4 a" b( e- [( G/ }9 z( K' g# y    b_cor = (price_20, premium_50)4 U' u" U+ {" T4 p
    c_cor = (price_20, premium_20). o) k* T  r; _- ^4 D
    d_cor = (price_50, premium_20)
/ [6 ^. ~2 }' i& s    e_cor = (price_80, premium_20)5 c, `% l) ^% W8 B# n7 c, ?+ j
    4 O% @) o7 m$ M/ I) z& b3 I
    k = (b_cor[1] - e_cor[1]) / (b_cor[0] - e_cor[0])6 v  i' }( |& r+ U& o8 M
    #依托BE构建指标( z; G  _, p  d& {" ~4 c
    tmp_df[&#39;性价比指标&#39;] = tmp_df.apply(lambda row: cal_price_effective(row, b_cor, e_cor), axis=1)" K& Z, G4 }. E+ \  X! L
  {4 M" t) W1 v
    tmp_df.sort_values(by=[&#39;交易日期&#39;, &#39;性价比指标&#39;], inplace=True)- X- L! k7 |$ R
    # tmp_df[&#39;偏移值_排名&#39;] = df.groupby(&#39;交易日期&#39;)[&#39;偏移值&#39;].rank(method=&#34;first&#34;)
5 I2 E/ g$ t7 {  [return tmp_df构建策略因子后其它代码参考以前帖子,这里不再赘述
/ b# b; ?/ C1 y: c% B+ R选取10只,回测结果如下:- J2 U7 q- `5 g! a0 z5 L" `
: Z5 N  U: X9 Q1 b
可转债轮动着重低转股溢价率的策略占优收益爆炸【python数字货币量化_21精华帖_策略第35篇】-9.jpg 4 a8 G  L' N! g- E  _2 \/ _. m! p

8 k1 e, ]; J9 I, J/ \ 可转债轮动着重低转股溢价率的策略占优收益爆炸【python数字货币量化_21精华帖_策略第35篇】-10.jpg
2 s; I1 M: ?6 U2 M2 x9 j; R9 f结束语
4 v. l  e7 O+ c; E  q2 P( |
. o% A4 c* h+ ]  @这两个回测不错的轮动策略,都属于包含高价的策略,我之前只关注一些低价标的,回测效果没有这么好,看来还是高价格的相对进攻性比较强,后期计划分出一部分资金参与一下;有对此策略感兴趣的朋友欢迎评论或私信讨论;
& P( H  {# w3 ^. |8 x8 E$ b6 W如果本篇对你有所帮助,请动动手指点个赞表示支持,感谢/ A( {3 l* ~+ A8 Y. N' P- O4 s
附件:6 A8 H9 z; P$ J! m* K5 o; x
( H3 [& {- {( K4 O
可转债轮动着重低转股溢价率的策略占优收益爆炸【python数字货币量化_21精华帖_策略第35篇】-11.jpg
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

267

金钱

0

收听

0

听众
性别

新手上路

金钱
267 元