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

[复制链接]
查看8347 | 回复0 | 2023-8-6 04:09:17 | 显示全部楼层 |阅读模式
引言% 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; { 可转债轮动着重低转股溢价率的策略占优收益爆炸【python数字货币量化_21精华帖_策略第35篇】-1.jpg ( 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 可转债轮动着重低转股溢价率的策略占优收益爆炸【python数字货币量化_21精华帖_策略第35篇】-2.jpg
+ 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
可转债轮动着重低转股溢价率的策略占优收益爆炸【python数字货币量化_21精华帖_策略第35篇】-3.jpg / ?  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[&#39;转股价值&#39;] >= min_val) & (q_df[&#39;转股价值&#39;] <= max_val)]
2 V5 q: B0 h# C) p1 F
- k8 r7 \7 a( q- y) m* q$ Q, g( w' _            q_df[&#39;转股溢价率&#39;] = q_df[&#39;转股溢价率&#39;] / 100- F. P. c" H2 J1 P% @) K
            # x轴是转股价值,y是转股溢价率0 q# h8 m  |, k0 h, b2 A8 n
            x = q_df[&#39;转股价值&#39;].tolist()- O2 F! z: I- W9 x
            y = q_df[&#39;转股溢价率&#39;].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(&#39;k&#39;) 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({&#39;quarter&#39;: date, &#39;k&#39;: k, &#39;k_m&#39;: 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
   &#34;&#34;&#34;
' @; Q3 h0 O* g8 G6 y! u# o   计算每天的因子数据
8 M. U* S$ v% i+ Q+ [1 ?   &#34;&#34;&#34;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(&#39;quarter&#39;))+ 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(&#39;k_m&#39;)
/ 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[[&#39;到期日&#39;, &#39;债券代码&#39;, &#39;转债名称&#39;]], on=&#39;债券代码&#39;, how=&#39;left&#39;,sort=True, indicator=True)- I+ w4 a6 {1 O, H

! J! \6 s4 g- ?1 U: k4 X2 l   tmp_df[&#39;转股溢价率&#39;] = tmp_df[&#39;转股溢价率&#39;] / 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[&#39;溢价率指标&#39;] = tmp_df[&#39;转股溢价率&#39;] + k_m * (tmp_df[&#39;转股价值&#39;] - 120); e& G3 }, s; ]- F1 H
   tmp_df.sort_values(by=[&#39;交易日期&#39;, &#39;溢价率指标&#39;], 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- \
可转债轮动着重低转股溢价率的策略占优收益爆炸【python数字货币量化_21精华帖_策略第35篇】-4.jpg 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
& ^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 = &#39;&#39;&#39;可转债数据.csv&#39;&#39;&#39;# N' V7 U' M2 \; c6 R
    df = pd.read_csv(file_path, encoding=&#39;gbk&#39;)( c* E: g, k5 w$ ^( M

2 M6 A! x- s. K/ D9 U    # 溢价率数据转化# `  X5 i1 s9 p. |2 Y
    df[&#39;premium_rt&#39;] = df[&#39;premium_rt&#39;].apply(lambda x: pd.to_numeric(str(x).replace(&#39;%&#39;, &#39;&#39;)))% |2 \3 H4 D2 D9 h% N% V. F
    df = df[(df[&#39;price&#39;] <= 200)]
2 G( a% u  W; r0 X    df = df[(df[&#39;premium_rt&#39;] <= 60)]
: _+ N) u/ P' W- n+ E& @4 H    x = df[&#39;price&#39;].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[&#39;premium_rt&#39;].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[&#39;高阶段距离差值&#39;] = 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=[&#39;高阶段距离差值&#39;], 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(&#34;ad:%s,bd:%s,be:%s&#34; % (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[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;]  # 用来正常显示中文标签
) v; k0 c+ C- N9 `1 Q' `; X# D, B    plt.rcParams[&#39;axes.unicode_minus&#39;] = False  # 用来正常显示负号1 D, }; U7 u4 i8 _$ v
    plt.plot(df[&#39;price&#39;].tolist(), df[&#39;premium_rt&#39;].tolist(), &#39;*&#39;, label=&#39;散点&#39;)
/ 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=&#39;gray&#39;, linestyle=&#39;--&#39;)& R. i9 \( t4 q
    plt.plot([x_min, x_max], [premium_50, premium_50], c=&#39;gray&#39;, linestyle=&#39;--&#39;)
9 `3 e) R2 Y" b2 J' v    plt.plot([x_min, x_max], [premium_80, premium_80], c=&#39;gray&#39;, linestyle=&#39;--&#39;)
" 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=&#39;gray&#39;, linestyle=&#39;--&#39;)
( x$ }; I" ?& a* e* g2 W    plt.plot([price_50, price_50], [y_min, y_max], c=&#39;gray&#39;, linestyle=&#39;--&#39;)  U  z$ h8 z' ^" I9 V6 D; d
    plt.plot([price_80, price_80], [y_min, y_max], c=&#39;gray&#39;, linestyle=&#39;--&#39;)
; 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=&#39;r&#39;, linestyle=&#39;-&#39;, label=&#39;低价段性价比&#39;)# 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=&#39;b&#39;, linestyle=&#39;-&#39;, label=&#39;中价段性价比&#39;)
/ [# 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=&#39;b&#39;, linestyle=&#39;-&#39;, label=&#39;中价段性价比&#39;)
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=&#39;g&#39;, linestyle=&#39;-&#39;, label=&#39;高价段性价比&#39;)- 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=&#39;g&#39;, linestyle=&#39;-&#39;, label=&#39;高价段性价比&#39;)
$ Q- E/ P/ a) {& q. n1 k$ f
* ^% g; X! L2 }6 a4 W2 m    plt.xlabel(&#39;价格(元)&#39;)
( r  _' U) r! B, r: N0 |0 E    plt.ylabel(&#39;转股溢价率&#39;)
; m$ n2 W6 E7 s* E# T; A, I    plt.legend(loc=1)  # 指定legend在图中的位置,类似象限的位置  y  `( e7 ~' Z% m! i
    plt.title(&#39;存量可转债价格与转股溢价率分布&#39;)' x3 o* q& [! N, E' j
    plt.show()这样我们也构建和研报中类似的三条线,我们依托这三条线中的高价段BE来构建因子% K% W3 M& R, z/ L

' a- ^+ L% x+ b/ g* V& j6 k1 ^ 可转债轮动着重低转股溢价率的策略占优收益爆炸【python数字货币量化_21精华帖_策略第35篇】-8.jpg
$ 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(&#39;2020-07-31&#39;):
: 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[[&#39;到期日&#39;, &#39;债券代码&#39;, &#39;转债名称&#39;]], on=&#39;债券代码&#39;, how=&#39;left&#39;,
: 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[&#39;close&#39;].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[&#39;转股溢价率&#39;] = tmp_df[&#39;转股溢价率&#39;] / 100
( f) j9 a# q0 B1 ]0 ~  A6 I8 \    y = tmp_df[&#39;转股溢价率&#39;].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[&#39;性价比指标&#39;] = 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=[&#39;交易日期&#39;, &#39;性价比指标&#39;], inplace=True)
. Z9 O; D3 T. N/ Q    # tmp_df[&#39;偏移值_排名&#39;] = df.groupby(&#39;交易日期&#39;)[&#39;偏移值&#39;].rank(method=&#34;first&#34;)! ]( 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
可转债轮动着重低转股溢价率的策略占优收益爆炸【python数字货币量化_21精华帖_策略第35篇】-9.jpg ; |/ u) G# c5 n' N" y( M. v4 d

6 j/ T& s( t- d0 c 可转债轮动着重低转股溢价率的策略占优收益爆炸【python数字货币量化_21精华帖_策略第35篇】-10.jpg
- 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
可转债轮动着重低转股溢价率的策略占优收益爆炸【python数字货币量化_21精华帖_策略第35篇】-11.jpg
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

266

金钱

0

收听

0

听众
性别

新手上路

金钱
266 元