[关闭]
@Channelchan 2017-11-27T14:06:29.000000Z 字数 7901 阅读 12065

如何设计信号选股方案并进行优化评估?

步骤

Step_1: 设计编写选股器算法的类,逐行计算合成DataFrame,返回MultiIndex

Step_2: 股票池与数据读取

Step_3: 初始化选股器的类,并获取选股信号

Step_4: 评估选股信号效果

Step_5: 优化选股算法的参数

Step_6: 测算不同参数组下选股信号的绩效

Step_7: 最优绩效结果可视化与保存Excel

Step_1: 设计编写选股器算法的类,逐行计算合成DataFrame,返回MultiIndex

  1. import pandas as pd
  2. from talib.abstract import MA
  3. from fxdayu_alphaman.selector.selector import Selector
  4. class DayMA(Selector):
  5. # 在此处设置选股器相关参数
  6. fast = 5
  7. slow = 10
  8. def calculate_MA_signal(self, data):
  9. candle_data = data[1].dropna()
  10. if len(candle_data) == 0:
  11. return
  12. fast = MA(candle_data, timeperiod=self.fast)
  13. slow = MA(candle_data, timeperiod=self.slow)
  14. f_over_s = fast - slow >0
  15. f_under_s = fast - slow <=0
  16. cross_over = (f_under_s.shift(1)) * f_over_s
  17. cross_under = - (f_over_s.shift(1))*f_under_s
  18. choice = pd.DataFrame(cross_over + cross_under)
  19. choice.columns = [data[0],]
  20. return choice
  21. def execute(self, pool, start, end, data=None, data_config=None):
  22. selector_result = map(self.calculate_MA_signal, data.iteritems())
  23. selector_result = pd.concat(selector_result, axis=1).stack()
  24. selector_result.index.names = ["date","asset"]
  25. return selector_result.loc[start:end]

Step_2: 股票池与数据读取

  1. from datetime import datetime
  2. from fxdayu_data import DataAPI
  3. # 测试参数设置
  4. start = datetime(2016, 1, 1)
  5. end = datetime(2017, 11, 24, 15)
  6. periods = (1, 5, 10)
  7. # 获取数据
  8. codes = DataAPI.info.codes('hs300')
  9. PN = DataAPI.candle(codes, 'D', start=start, end=end, adjust="after")

Step_3: 初始化选股器的类,并获取选股信号

  1. from fxdayu_alphaman.selector.admin import Admin
  2. selector = DayMA()
  3. s_admin = Admin()
  4. result = s_admin.instantiate_selector_and_get_selector_result("DayMA", codes, start, end, Selector=selector, data=PN)
  5. print(result.tail())
date                 asset      
2017-11-24 15:00:00  601997.XSHG    0
                     601998.XSHG    0
                     603160.XSHG    1
                     603858.XSHG    0
                     603993.XSHG    0
dtype: object
  1. from fxdayu_alphaman.selector.utility import read_benchmark
  2. from fxdayu_alphaman.selector.selector_analysis import *
  3. hs300 = read_benchmark(start, end)
  4. hs300_return = get_stocklist_mean_return(hs300["index"],"hs300",start,end,hs300["close"],periods=periods)
  5. print (hs300_return)
                                           1         5         10
factor_quantile date                                             
hs300           2016-01-01 15:00:00  0.000000  0.000000  0.000000
                2016-01-02 15:00:00  0.000000  0.000000  0.000000
                2016-01-03 15:00:00  0.000000  0.000000  0.000000
                2016-01-04 15:00:00  0.002412 -0.080094 -0.097879
                2016-01-05 15:00:00  0.017544 -0.075621 -0.073491
                2016-01-06 15:00:00 -0.069334 -0.108461 -0.103234
                2016-01-07 15:00:00  0.020392 -0.022101 -0.064665
                2016-01-08 15:00:00 -0.050307 -0.072237 -0.073805
                2016-01-09 15:00:00  0.000000  0.000000  0.000000
                2016-01-10 15:00:00  0.000000  0.000000  0.000000
                2016-01-11 15:00:00  0.007286 -0.019333 -0.019909
                2016-01-12 15:00:00 -0.018606  0.002304 -0.085580
                2016-01-13 15:00:00  0.020815  0.005862 -0.071463
                2016-01-14 15:00:00 -0.031922 -0.043525 -0.114171
                2016-01-15 15:00:00  0.003848 -0.001690 -0.055356
                2016-01-16 15:00:00  0.000000  0.000000  0.000000
                2016-01-17 15:00:00  0.000000  0.000000  0.000000
                2016-01-18 15:00:00  0.029511 -0.000588 -0.073363
                2016-01-19 15:00:00 -0.015122 -0.087682 -0.081223
                2016-01-20 15:00:00 -0.029307 -0.076875 -0.071113
                2016-01-21 15:00:00  0.010421 -0.073860 -0.031347
                2016-01-22 15:00:00  0.004956 -0.053757 -0.048072
                2016-01-23 15:00:00  0.000000  0.000000  0.000000
                2016-01-24 15:00:00  0.000000  0.000000  0.000000
                2016-01-25 15:00:00 -0.060207 -0.072818 -0.058225
                2016-01-26 15:00:00 -0.003455  0.007080  0.032828
                2016-01-27 15:00:00 -0.026137  0.006242  0.045377
                2016-01-28 15:00:00  0.032354  0.045904  0.070062
                2016-01-29 15:00:00 -0.015288  0.006008  0.035807
                2016-01-30 15:00:00  0.000000  0.000000  0.000000
...                                       ...       ...       ...
                2017-10-25 15:00:00  0.004182  0.004946  0.017868
                2017-10-26 15:00:00  0.007109  0.000889  0.020613
                2017-10-27 15:00:00 -0.003046 -0.007278  0.022362
                2017-10-28 15:00:00  0.000000  0.000000  0.000000
                2017-10-29 15:00:00  0.000000  0.000000  0.000000
                2017-10-30 15:00:00 -0.000748  0.002786  0.029516
                2017-10-31 15:00:00 -0.002521  0.011863  0.023119
                2017-11-01 15:00:00  0.000128  0.012858  0.019279
                2017-11-02 15:00:00 -0.001108  0.019707  0.026989
                2017-11-03 15:00:00  0.007060  0.029857  0.032096
                2017-11-04 15:00:00  0.000000  0.000000  0.000000
                2017-11-05 15:00:00  0.000000  0.000000  0.000000
                2017-11-06 15:00:00  0.008297  0.026656  0.030575
                2017-11-07 15:00:00 -0.001539  0.011124  0.040316
                2017-11-08 15:00:00  0.006890  0.006339  0.044358
                2017-11-09 15:00:00  0.008835  0.007142  0.006502
                2017-11-10 15:00:00  0.003930  0.002174 -0.001875
                2017-11-11 15:00:00  0.000000  0.000000  0.000000
                2017-11-12 15:00:00  0.000000  0.000000  0.000000
                2017-11-13 15:00:00  0.000000  0.000000  0.000000
                2017-11-14 15:00:00  0.000000  0.000000  0.000000
                2017-11-15 15:00:00  0.000000  0.000000  0.000000
                2017-11-16 15:00:00  0.000000  0.000000  0.000000
                2017-11-17 15:00:00  0.000000  0.000000  0.000000
                2017-11-18 15:00:00  0.000000  0.000000  0.000000
                2017-11-19 15:00:00  0.000000  0.000000  0.000000
                2017-11-20 15:00:00  0.000000  0.000000  0.000000
                2017-11-21 15:00:00  0.000000  0.000000  0.000000
                2017-11-22 15:00:00  0.000000  0.000000  0.000000
                2017-11-23 15:00:00  0.000000  0.000000  0.000000

[693 rows x 3 columns]
  1. performance = s_admin.calculate_performance("DayMA",
  2. result[result>0], #结果大于0的(选出的)
  3. start,
  4. end,
  5. periods=periods,
  6. benchmark_return=hs300_return)

Step_4: 评估选股信号效果

  1. import alphalens
  2. def plot_performance(performance):
  3. # 1.收益概率密度分布图
  4. plot_distribution_of_returns(performance["upside_return"],period=10,return_type="upside")
  5. # 2.收益概率密度分布图-提琴盒图
  6. plot_stock_returns_violin(performance["upside_return"],return_type="upside")
  7. plot_stock_returns_violin(performance["downside_return"],return_type="downside")
  8. # 3.累积收益曲线
  9. alphalens.plotting.plot_cumulative_returns_by_quantile(performance["mean_return"],period=10)
  10. plt.show()
  11. plot_performance(performance)

output_11_1.png-21.7kB

output_11_2.png-18.6kB

output_11_3.png-19.5kB

output_11_4.png-44.8kB

  1. performance["upside_return"][10].quantile(0.75)
0.07266650400620958
  1. performance["downside_return"][10].quantile(0.25)
-0.062460970024979176

Step_5: 优化选股算法的参数

  1. #优化选股器参数
  2. para_range_dict = {"fast":range(2,7,1),"slow":range(10,20,1)}
  3. results_list, para_dict_list = s_admin.enumerate_parameter("DayMA",
  4. para_range_dict,
  5. codes,
  6. start,
  7. end,
  8. Selector=selector,
  9. data=PN,
  10. parallel=False)
  1. len(results_list)
50
  1. # 生成策略名称与策略结果的列表
  2. strategy_dict = {}
  3. for i in range(len(results_list)):
  4. strategy_name = "DayMA+" + str(para_dict_list[i])
  5. strategy_result = results_list[i][results_list[i]>0]
  6. strategy_dict[strategy_name]=strategy_result

Step_6: 测算不同参数组下选股信号的绩效

  1. performance_list = s_admin.show_strategies_performance(strategy_dict,
  2. start,
  3. end,
  4. periods=periods,
  5. benchmark_return=hs300_return,
  6. parallel=False)
  1. # 按夏普率对选股信号-10天持仓目标寻优
  2. performance_rank = s_admin.rank_performance(performance_list,
  3. target_period=10,
  4. target_indicator="Sharpe ratio",
  5. ascending=False)
  6. print (performance_rank[0].strategy_name)
  7. print (performance_rank[0].key_performance_indicator)
DayMA+{'fast': 6, 'slow': 15}
{'period_1': Annual return          -0.083201
Cumulative returns     -0.212494
Annual volatility       0.199780
Sharpe ratio           -0.334403
Calmar ratio           -0.249621
Stability               0.089731
Max drawdown           -0.333308
Omega ratio             0.917034
Sortino ratio          -0.458437
Skew                   -0.473311
Kurtosis               18.072241
Tail ratio              1.007174
Daily value at risk    -0.025435
Alpha                  -0.127551
Beta                    0.841140
dtype: float64, 'period_5': Annual return          0.073386
Cumulative returns     0.215008
Annual volatility      0.414937
Sharpe ratio           0.374523
Calmar ratio           0.140593
Stability              0.011811
Max drawdown          -0.521978
Omega ratio            1.092453
Sortino ratio          0.589663
Skew                   1.078674
Kurtosis               7.584723
Tail ratio             0.933924
Daily value at risk   -0.051660
Alpha                 -0.117579
Beta                   0.743836
dtype: float64, 'period_10': Annual return           0.383552
Cumulative returns      1.441954
Annual volatility       0.536604
Sharpe ratio            0.867059
Calmar ratio            0.646380
Stability               0.206264
Max drawdown           -0.593384
Omega ratio             1.221870
Sortino ratio           1.367665
Skew                    1.316101
Kurtosis               13.863635
Tail ratio              1.012346
Daily value at risk    -0.065759
Alpha                  -0.129780
Beta                    0.679332
dtype: float64}

Step_7: 最优绩效结果可视化与保存Excel

  1. plot_performance(performance_rank[0])

output_22_1.png-23.4kB

output_22_2.png-19.8kB

output_22_3.png-20.6kB

output_22_4.png-44.7kB

  1. performance_rank[0]["upside_return"][10].quantile(0.75)
0.07279166815279806
  1. performance_rank[0]["downside_return"][10].quantile(0.25)
-0.05795350860912572
  1. import numpy as np
  2. selector_sheet = s_admin.instantiate_selector_and_get_selector_result("DayMA",
  3. codes,
  4. start,
  5. end,
  6. Selector=selector,
  7. data=PN,
  8. para_dict={"slow":16, "fast":4})
  9. selector_sheet = selector_sheet.unstack().replace(np.nan,0)
  10. selector_sheet.to_excel('selector_opt.xlsx')
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注