打开股票量化的黑箱 (自己动手写一个印钞机) 第二章

1,304 阅读6分钟
原文链接: www.jianshu.com

作者:阿布🐶
未经本人允许禁止转载
ipython notebook git版本

目录章节地址:
自己动手写一个印钞机 第一章
自己动手写一个印钞机 第二章
自己动手写一个印钞机 第三章
自己动手写一个印钞机 第四章
自己动手写一个印钞机 第五章
自己动手写一个印钞机 第六章
自己动手写一个印钞机 第七章
自己动手写一个印钞机 附录章

股票量化专题地址,请关注,谢谢!


非均衡胜负收益带来的必然非均衡胜负比例,目标由因子的能力解决一部分,模式识别提升关键的一部分

本章开始说文章的核心了,模式识别提升关键的一部分 本章的内容主要是通过机器学习如svm,随机森林等对股票模式识别的初步探索,俗称罪恶的第一步,但还是要坚定的迈出,毕竟目标是印钞机

下面运行因子对多年数据进行回测,模式识别中基本的需求就是生成训练集数据与测试集数据,对训练集的数据抽取特质,总结规律,在测试集上指导交易,与没有指导交易的测试集进行比对,查看效果。

BuyGoldenFactor.g_enable_filter_ml = True # 回测因子的历史且结果集加入机器学习需要的数据
BuyGoldenFactor.g_enable_snap = True # 生成交易这一时刻60日图像,为深度学习准备, 详情见第四章
buy_factors = [{'XD': 42, 'class': BuyGoldenFactorClass, 'draw': True}]

# n_folds: 6年数据回测生成五年单子
# train_test_split:回测时预留一份股票代码表作为测试集,生成9份训练集,当use_last_test为True 时只用一份测试股票代码表进行因子回测
# ret_cnt_need = 0:回测所有股票
out, orders_pd_train_snap = MetricsManger.make_metrics_rsc_mul_symbol_grid(buy_factors, n_folds=6, 
    score_type=METRICSTYPE.SYSMBOL_R_SCORES_GOLDEN.value, ret_cnt_need=0, train_test_split=True, 
    use_last_test=False, force_one_process=False)

pd.options.display.max_columns = 40
orders_pd_train_snap.tail(2) # 看看添加了提供机器学习数据的pandas

由于简书不支持html的表格,完整表格请查阅git上完整版ipython notebook



这些特征都是什么比如deg_windowPd就是买入股票这一天前42天k线图的线性拟合斜率,deg_hisWindowPd是252天k线图的线性拟合斜率,它们代表了买入前股票的一种状态也就能代表一种特征,你可以理解为这些特征都是发生交易前的一些状态的量化值特征,暂时没有必要全部深入了解,知道是特征就行。

下面生成测试集数据

BuyGoldenFactor.g_enable_fiter = False
BuyGoldenFactor.g_enable_snap = True
buy_factors = [{'XD': 42, 'class': BuyGoldenFactorClass, 'draw': True}]
out, orders_pd_test = MetricsManger.make_metrics_rsc_mul_symbol_grid(buy_factors, n_folds=6, 
    score_type=METRICSTYPE.SYSMBOL_R_SCORES_GOLDEN.value, ret_cnt_need=0, train_test_split=False, 
    use_last_test=True, force_one_process=False)

orders_pd_train_snap.shape, orders_pd_test_snap.shape
    # out
    ((44412, 32), (4956, 32))

对训练集及测试集的结果进行大体的度量:主要就是看看非均衡胜负收益带来的必然非均衡胜负比例,目标由因子的能力解决一部分效果怎么样

首先是训练集结果数据

train_ump = UmpMainClass(orders_pd_train_snap, MlFiterGoldenPdClass)
train_ump.show_general()
    # out
    all fit order = (41225, 32)
    win rate = 0.493559733172
    profit_cg.sum() = 281.687935222
    win mean = 0.0770327160087 loss_mean = -0.061738192442

output_14_1.png

接下来是测试集结果数据

test_ump = UmpMainClass(orders_pd_test_snap, MlFiterGoldenPdClass)
test_ump.show_general()
    # out
    all fit order = (4612, 32)
    win rate = 0.5
    profit_cg.sum() = 37.4002795407
    win mean = 0.076550446692 loss_mean = -0.0605681543452

output_15_1.png

显示在所有有结果的单子中胜率可以接近一半,且每次赢的0.07比每次输的0.06多,
但是贪婪的我仍然认为有优化空间,这个空间就是利用这个因子产生的输出数据
作为特征识别基础,提炼特征,指导交易,

模式识别提升关键的一部分

下面我们看看如何做到的呢

首先确认ml封装库是否能正常运行

test_fiter_more = MlFiterClass.create_test_more_fiter()

学习曲线

test_fiter_more.estimator.logistic_regression()
test_fiter_more.plot_learning_curve()

output_20_0.png

特征权重

test_fiter.importances_coef_pd()

树逻辑图

test_fiter.plot_graphviz_tree()

output_24_0.png

混淆矩阵

test_fiter_more.plot_confusion_matrices()
    # out
    [[453  96]
     [100 242]]

output_26_1.png

roc

test_fiter_more.plot_roc_estimator()

output_28_1.png

特征选择

test_fiter_more.feature_selection()
    # out
    RFE selection
                 ranking support
    SibSp              1    True
    Parch              1    True
    Cabin_No           1    True
    Cabin_Yes          6   False
    Embarked_C         2   False
    Embarked_Q         5   False
    Embarked_S         3   False
    Sex_female         8   False
    Sex_male           1    True
    Pclass_1           4   False
    Pclass_2           7   False
    Pclass_3           1    True
    Age_scaled         1    True
    Fare_scaled        1    True

    RFECV selection
                 ranking support
    SibSp              1    True
    Parch              2   False
    Cabin_No           1    True
    Cabin_Yes          7   False
    Embarked_C         3   False
    Embarked_Q         8   False
    Embarked_S         4   False
    Sex_female         1    True
    Sex_male           9   False
    Pclass_1           5   False
    Pclass_2           6   False
    Pclass_3           1    True
    Age_scaled         1    True
    Fare_scaled        1    True

决策边界

test_fiter.plot_decision_function()

output_32_0.png

output_32_1.png

train test score

test_fiter_more.cross_val_accuracy_score()
    # out
    accuracy mean: 0.776812507093
    array([ 0.75555556,  0.72222222,  0.73033708,  0.75280899,  0.83146067,
    0.78651685,  0.80898876,  0.71910112,  0.82022472,  0.84090909])

切换使用其它学习方法

test_fiter_more.estimator.adaboost_classifier()
test_fiter_more.cross_val_accuracy_score()
    # out
    accuracy mean: 0.810433548973
    array([ 0.78888889,  0.78888889,  0.78651685,  0.80898876,  0.84269663,
    0.78651685,  0.82022472,  0.82022472,  0.79775281,  0.86363636])

可以证明封装库没有问题,可以放心使用,下一步上真正的股票数据

由252,60, 42天组成的走势数剧作为特质开始

from MlFiterDegPd import MlFiterDegPdClass
deg = MlFiterDegPdClass(orderPd=orders_pd_train_snap)
deg.df.head()

deg().estimator.svc()
deg().cross_val_accuracy_score()
    # out
    accuracy mean: 0.491279520472
    array([ 0.48920689,  0.51758428,  0.49987873,  0.49551298,  0.48168809,
    0.4887218 ,  0.47610963,  0.47355653,  0.4853191 ,  0.50521718])

0.49的准确率,相当于是乱猜 是不是特征选择的不好呢,换一些特征试试

from MlFiterMainPd import MlFiterMainPdClass
main = MlFiterMainPdClass(orderPd=orders_pd_train_snap)
main.df.head()

main().cross_val_accuracy_score()
    # out
    accuracy mean: 0.493608245706
    array([ 0.5008489 ,  0.49890856,  0.49793839,  0.48678147,  0.50303177,
    0.47125879,  0.49648314,  0.49369238,  0.49332686,  0.49381218])

0.49的准确率,还是乱猜 是不是特征太少了,构建一个特征多的试试

from MlFiter import MlFiterClass
order_has_ret = orders_pd_train_snap[(orders_pd_train_snap.result <> 0)]

all_pd = order_has_ret.filter(['result', 'deg_hisWindowPd', 'deg_windowPd', 'deg_60WindowPd', 'atr_std', 'jump_power', 
                               'diff_days', 'wave_score1', 'wave_score2', 'wave_score23'])
train_np = all_pd.as_matrix()
y = train_np[:, 0]
x = train_np[:, 1:]
all_filter = MlFiterClass(x, y, all_pd)
all_pd.head()

# 这回使用随机森林
all_filter.estimator.random_forest_classifier()
all_filter.cross_val_accuracy_score()
    # out
    accuracy mean: 0.505349477658
    array([ 0.48678147,  0.50788261,  0.53019646,  0.50497211,  0.51297599,
    0.46058695,  0.51564395,  0.50994663,  0.4942975 ,  0.53021111])

0.50的准确率,这算是有所提升吗?😥

下面把数据离散化后,换种分类器测试

deg = MlFiterDegPdClass(orderPd=orders_pd_train_snap, dummies=True, invoke_hmm=False,
                       invoke_pca=False)
deg.df.head()

由于简书不支持html的表格,完整表格请查阅git上完整版ipython notebook



上边封住好了的,在离散值的选择上不是瞎来的,会通过可视化来选择离散值bins,通过数据来指导数据最终指导交易

deg().estimator.random_forest_classifier()
deg().cross_val_accuracy_score()
    # out
    accuracy mean: 0.487590577522
    array([ 0.48217317,  0.51564395,  0.4962406 ,  0.49890856,  0.49745331,
    0.48338588,  0.49527043,  0.45414847,  0.44479495,  0.50788644])

结果还是乱猜

用其它等等方式仍然是胡猜,自己写的类似adaboost依然效果很差, 通过非均衡概率降低假阳,提高假阴的方式,最后统计所有测试集样本的判别概率发现其实还瞎猜

提高分类数量,设置阀值,提高准确率的方案

通过将profit cg qcut 100份分类

orders_pd_train_snap.profit_cg.fillna(0, inplace=True)
order_has_ret = orders_pd_train_snap[(orders_pd_train_snap.result <> 0)]
n_class = 100
order_has_ret['class'] = pd.qcut(order_has_ret.profit_cg, n_class, labels=range(0, n_class))
order_has_ret['class'] = order_has_ret['class'].astype(int)
ZLog.info(np.unique(order_has_ret['class']))

deg_pd = order_has_ret.filter(['class', 'result', 'deg_hisWindowPd', 'deg_windowPd', 'deg_60WindowPd'])
train_np = deg_pd.as_matrix()
y = train_np[:, 0]
x = train_np[:, 1:]
deg = MlFiterClass(x, y, deg_pd, force_clf=True)
deg_pd.head()

  • y为class train_test_split进行分类
  • 使用cv数据集的 predict < class阀值 使用result==0的情况查看概率
from sklearn.cross_validation import train_test_split
from sklearn.metrics import accuracy_score
from sklearn.metrics import classification_report

deg.estimator.random_forest_classifier()

train_df, cv_df = train_test_split(deg.df, test_size=0.1, random_state=0)

fiter = deg.get_fiter()
fiter.fit(train_df.as_matrix()[:, 2:], train_df.as_matrix()[:, 0])

predictions = fiter.predict(cv_df.as_matrix()[:, 2:])

cv_df['predict'] = predictions
cv_df.head()

cv_df['predict'].value_counts().sort_index().head(10)
    # out
    0.0    56
    1.0    50
    2.0    43
    3.0    47
    4.0    44
    5.0    45
    6.0    47
    7.0    30
    8.0    46
    9.0    39
    Name: predict, dtype: int64

for threshold in np.arange(0, 10):
    ppv = cv_df[cv_df['predict'] 

threshold: 0,1,达到0.6了 但是数量上只有100多个,之后会有使用gmm-hmm的方式继续扩展这种思路,提高收益

只能说最后一种的这个思想可以作为扩展使用,实际中由于 '非均衡胜负收益' 很难带来质的好转,突然想到阿西莫夫的小说基地,对心理史学的最开始的评估,‘可能但是不可行’,我们的印钞机之路是否也是这样呢,下一章开始就是真正的印钞机之路了,一个即可能又可行之路!!! 下一章开始将使用深度学习方法来训练数据,提高胜率主要是卷机神经网络的使用


下一章地址
自己动手写一个印钞机 第三章


感谢🙏您能有耐心看到这里

如果有什么问题可以加阿布的微信

微信号:aaaabbbuu


mmexport1475383814280.jpg