基于上篇文章提到的思路,个人觉得你不能用A来预测A,所以我打算换一种数据。 上篇文章 《算法-基于MACD的Adaboost股价涨跌预测模型》 虽然给出了adaboost算法,但是并没有完全正确的表达,尤其是在权重如何处理上,也就是如何对待那些被误分的样本。 所以打算更严谨的来对待这个算法,本着不要用错误的方法得出正确的结论的原则,我修正了我的adaboost算法,由于需要用大量的数据进行测试,我决定把java代码移植为C/C++版本以期获得更高的训练速度。好吧,下面我介绍一下修正后的算法。我再一次参考李航的《统计学习方法》 和《量价秘密》这两本书,我决定放弃我的阀值分类器转而使用最简单的感知器线性分类器,事实上股价的涨跌和成交量本身就不是一种线性关系,而是一种复杂的非线性关系,而且这种关系由于其他变量的作用变得模糊,我们只能大概判断,却无法精确定性,由此使用弱分类器是合适的。这个版本的预测只是一个阶段性的,后期我还会继续寻找非线性的简单分类器来训练我的数据。在使用adaboost的时候,不得不提到就是error率如何计算,特别是在样本分布不均匀的时候,我们必须分别计算正样本和负样本的分类准确率,这个前提条件下整体的分类准确率才有意义。举个例子,假如正样本个数51个,负样本数据49个,假如分类器毫无理由的完全输出1,即所有的样本都分类为正样本,那么可以获得49%的准确率,完全符合adaboost的算法框架,实际上,这种分类器是毫无意义的,训练出来也毫无决策能力,因为它受样本分布影响,也就是说涨的多你就赚,跌的多你就亏。 如果我们将正负样本分开,51个正样本的错误率是40%, 49个负样本的错误率是42%,那么整体的错误率就会下降:51*40%+49*42%=40.98, 也就是错误分的样本数为40.98个,那么错误率也就是40.98%,这样计算出来错误率才有意义,我不得不百般的强调这个结论,因为在训练的时候我确实因为没有分别对待正样本和负样本而导致了前面提到的垃圾分类器诞生。对于简单的线性感知器,我有一点看法,具体实现请参考李航的《统计学习方法》,训练非常的简单:
for(int epoch = 0; epoch < EPOCH; epoch++){
//sequence gradient descent. not stochastic.
for(int i = 0; i < rows; i++){
double res = predict(trainX[i], colsX);
if(trainY[i] * res <= 0){
//update W and b.
for(int j = 0; j < colsX; j++){
mWeights[j] += lr * trainY[i] * trainX[i][j];//ok
}
mBias += lr * trainY[i];//ok
}
}
}
double predict(double* trainX, int colsX){
double res = 0;
for(int i = 0; i < colsX; i++){
res += mWeights[i] * trainX[i];
}
res += mBias;
return res;
}
对于Adaboost算法错误率的修正
double WeakClassifier::calculateAdaBoostError(double** inputX, double* inputY, double* weights, int* rightOrWrong, const int rows, const int colsX){
if(inputX == NULL || inputY == NULL || rightOrWrong == NULL || weights == NULL){
printf("WeakClassifier::calculateAdaBoostError(double**, double*, double*, int*, int, int), param NULL\n");
int paramNull = 9;
throw paramNull;
}
double err = 0;
for(int i = 0; i < rows; i++){
double res = predict(inputX[i], colsX);
if(inputY[i] * res <= 0){
rightOrWrong[i] = WRONG;
err += weights[i];
//err++;
}else{
rightOrWrong[i] = RIGHT;
}
}
//return err / rows;
return err;
}
我为什么在参考了《量价秘密》后决定用成交量来预测股价呢,而且使用线性模型,这里解释一下。量价秘密那本书里通过比较成交量的大小来决定买入和卖出信号的触发,比较本身就是一种线性关系,所以我使用WX+B的方式来进行判断,通过对成交量进行线性组合,调节W和B就可以组合出成交量的比较,也就有了通过量的比较的弱分类器。
关于数据,我依然使用均成交量,并且使用了多日的均成交量,由于股价的短期的不可预测性,我将预测周期延长至3天。
通过训练:
./test.exe -e 3000 -c 600704
train epoch is 3000 code is -c
startrow=0 endrow=51000 startcol=1 endcol=16
startrow=0 endrow=4623 startcol=1 endcol=16
start training......
Epoch [ ] 0 ECR=100.0000 EP=0.3169 EN=0.6166 SUME=0.4651 E=0.4651 IR0=1173.1940 IR1=-4018.6180 SUMIR=-2845.4240
Epoch [GOT] 1 ECR=100.0000 EP=0.4761 EN=0.4381 SUME=0.4569 E=0.4569 IR0=12071.1190 IR1=-14916.5430 SUMIR=-2845.4240
Epoch [GOT] 6 ECR=100.0000 EP=0.4868 EN=0.4209 SUME=0.4567 E=0.4678 IR0=11375.0000 IR1=-14220.4240 SUMIR=-2845.4240
Epoch [GOT] 9 ECR=100.0000 EP=0.4350 EN=0.4300 SUME=0.4524 E=0.4466 IR0=4615.1350 IR1=-7460.5590 SUMIR=-2845.4240
Epoch [GOT] 10 ECR=100.0000 EP=0.3227 EN=0.4616 SUME=0.4465 E=0.4280 IR0=14724.8560 IR1=-17570.2800 SUMIR=-2845.4240
Epoch [ ] 100 ECR=2.3039 EP=0.5383 EN=0.5726 SUME=0.5553 E=0.5302 IR0=-1646.3840 IR1=-1199.0400 SUMIR=-2845.4240
Epoch [ ] 200 ECR=2.3039 EP=0.7418 EN=0.2352 SUME=0.4913 E=0.4943 IR0=1293.3930 IR1=-4138.8170 SUMIR=-2845.4240
Epoch [ ] 300 ECR=2.3039 EP=0.5250 EN=0.5844 SUME=0.5544 E=0.5334 IR0=-23511.8240 IR1=20666.4000 SUMIR=-2845.4240
Epoch [ ] 400 ECR=2.3039 EP=0.4121 EN=0.7739 SUME=0.5910 E=0.5561 IR0=-20503.8920 IR1=17658.4680 SUMIR=-2845.4240
Epoch [ ] 500 ECR=2.3039 EP=0.6112 EN=0.4390 SUME=0.5261 E=0.5163 IR0=2418.4420 IR1=-5263.8660 SUMIR=-2845.4240
Epoch [ ] 700 ECR=2.3039 EP=0.4904 EN=0.6286 SUME=0.5587 E=0.5341 IR0=-11965.5530 IR1=9120.1290 SUMIR=-2845.4240
Epoch [ ] 800 ECR=2.3039 EP=0.4483 EN=0.6330 SUME=0.5396 E=0.5236 IR0=-7478.3960 IR1=4632.9720 SUMIR=-2845.4240
Epoch [ ] 900 ECR=2.3039 EP=0.5614 EN=0.4788 SUME=0.5205 E=0.5111 IR0=5078.3710 IR1=-7923.7950 SUMIR=-2845.4240
Epoch [ ] 1000 ECR=2.3039 EP=0.4377 EN=0.7497 SUME=0.5920 E=0.5560 IR0=-30847.1960 IR1=28001.7720 SUMIR=-2845.4240
Epoch [ ] 1100 ECR=2.3039 EP=0.4969 EN=0.5871 SUME=0.5415 E=0.5227 IR0=-18519.4230 IR1=15673.9990 SUMIR=-2845.4240
Epoch [ ] 1200 ECR=2.3039 EP=0.4789 EN=0.7170 SUME=0.5966 E=0.5544 IR0=-21886.6390 IR1=19041.2150 SUMIR=-2845.4240
Epoch [ ] 1300 ECR=2.3039 EP=0.4268 EN=0.6292 SUME=0.5269 E=0.5148 IR0=-10134.1010 IR1=7288.6770 SUMIR=-2845.4240
Epoch [ ] 1400 ECR=2.3039 EP=0.4437 EN=0.6296 SUME=0.5356 E=0.5187 IR0=-16387.0800 IR1=13541.6560 SUMIR=-2845.4240
Epoch [ ] 1500 ECR=2.3039 EP=0.4849 EN=0.6207 SUME=0.5521 E=0.5264 IR0=-10468.6150 IR1=7623.1910 SUMIR=-2845.4240
Epoch [ ] 1700 ECR=2.3039 EP=0.4401 EN=0.7248 SUME=0.5809 E=0.5496 IR0=-17702.6790 IR1=14857.2550 SUMIR=-2845.4240
Epoch [ ] 2000 ECR=2.3039 EP=0.4878 EN=0.6360 SUME=0.5611 E=0.5330 IR0=-11540.4570 IR1=8695.0330 SUMIR=-2845.4240
Epoch [ ] 2100 ECR=2.3039 EP=0.6207 EN=0.4958 SUME=0.5589 E=0.5316 IR0=-17458.0150 IR1=14612.5910 SUMIR=-2845.4240
Epoch [ ] 2200 ECR=2.3039 EP=0.4197 EN=0.7084 SUME=0.5625 E=0.5350 IR0=-15700.9920 IR1=12855.5680 SUMIR=-2845.4240
Epoch [ ] 2300 ECR=2.3039 EP=0.3692 EN=0.7865 SUME=0.5756 E=0.5458 IR0=-16695.8020 IR1=13850.3780 SUMIR=-2845.4240
Epoch [ ] 2400 ECR=2.3039 EP=0.4680 EN=0.7610 SUME=0.6129 E=0.5676 IR0=-25387.5070 IR1=22542.0830 SUMIR=-2845.4240
Epoch [ ] 2500 ECR=2.3039 EP=0.5393 EN=0.6183 SUME=0.5784 E=0.5439 IR0=-22889.1490 IR1=20043.7250 SUMIR=-2845.4240
Epoch [ ] 2600 ECR=2.3039 EP=0.6507 EN=0.3491 SUME=0.5016 E=0.4994 IR0=5327.8050 IR1=-8173.2290 SUMIR=-2845.4240
Epoch [ ] 2700 ECR=2.3039 EP=0.4453 EN=0.6017 SUME=0.5226 E=0.5135 IR0=-7558.7720 IR1=4713.3480 SUMIR=-2845.4240
Epoch [ ] 2800 ECR=2.3039 EP=0.4725 EN=0.7312 SUME=0.6005 E=0.5599 IR0=-22751.3970 IR1=19905.9730 SUMIR=-2845.4240
calculate trained model:E0=0.3227 E1=0.4616
Use model 0
这里解释下各个参数,epoch[ ]代表例行检查输出,表明我的程序在跑epoch[ GOT ]代表找到了一个弱分类器。
ECR为错误分类样本的权重小于平均值的比例,EP代表正样本的错误率, EN代表负样本的错误率, SUME代表整体错误率,E是adaboost模型的错误率,IR0代表系统发出买入信号的利润率, IR1代表系统发出卖出信号时,如果你买入后将获得的利润率,好的模型应该是IR0大于0 IR1小于0,所以我过滤掉了那些不符合这个条件,但是准确率符合条件的若分类器。
train over!! 4 weak classifier(s) was trained !!!
MODEL0: [20150616] [ERROR] BLF: 0.26 POINT= -5.55 IR0= -5.55
MODEL0: [20150618] [ERROR] BLF: 0.04 POINT= -3.66 IR0= -9.21
MODEL0: [20150624] [ERROR] BLF: 0.73 POINT= -15.23 IR0= -24.44
MODEL0: [20150625] [ERROR] BLF: 0.20 POINT= -15.03 IR0= -39.46
MODEL0: [20150626] [ERROR] BLF: 0.90 POINT= -19.59 IR0= -59.05
MODEL0: [20150630] [ERROR] BLF: 0.24 POINT= -19.42 IR0= -78.48
MODEL0: [20150701] [ERROR] BLF: 1.86 POINT= -19.44 IR0= -97.92
...........................................
..............................................
.................................................
MODEL0: [20160314] [ OK ] BLF: 0.20 POINT= 6.51 IR0= 745.22
MODEL0: [20160315] [ OK ] BLF: 0.21 POINT= 5.79 IR0= 751.01
MODEL0: [20160321] [ OK ] BLF: 0.10 POINT= 6.70 IR0= 757.71
MODEL0: [20160322] [ OK ] BLF: 0.02 POINT= 2.11 IR0= 759.82
MODEL0: [20160329] [ OK ] BLF: 0.46 POINT= 1.94 IR0= 761.76
MODEL0: [20160330] [ OK ] BLF: 0.03 POINT= 3.77 IR0= 765.54
MODEL0: [20160406] [ OK ] BLF: 0.96 POINT= 10.83 IR0= 776.37
MODEL0: [20160407] [ OK ] BLF: 0.03 POINT= 7.66 IR0= 784.03
MODEL0: [20160413] [ OK ] BLF: 0.30 POINT= 4.35 IR0= 788.38
MODEL0: [20160421] [ERROR] BLF: 0.11 POINT= -6.98 IR0= 781.40
MODEL0: [20160428] [ OK ] BLF: 0.30 POINT= 2.95 IR0= 784.35
MODEL0: [20160509] [ERROR] BLF: 0.09 POINT= -12.38 IR0= 771.97
MODEL0: [20160607] [ OK ] BLF: 0.42 POINT= 8.74 IR0= 780.71
MODEL0: [20160608] [ OK ] BLF: 0.17 POINT= 7.49 IR0= 788.20
MODEL0: [20160620] [ OK ] BLF: 0.20 POINT= 5.13 IR0= 793.33
MODEL0: [20160621] [ OK ] BLF: 0.11 POINT= 2.15 IR0= 795.48
MODEL0: [20160628] [ OK ] BLF: 0.32 POINT= 4.38 IR0= 799.87
MODEL0: [20160629] [ OK ] BLF: 0.04 POINT= 5.75 IR0= 805.62
MODEL0: [20160708] [ OK ] BLF: 0.05 POINT= 0.41 IR0= 806.03
MODEL0: [20160721] [ OK ] BLF: 0.33 POINT= 4.61 IR0= 810.63
MODEL0: [20160722] [ OK ] BLF: 0.23 POINT= 6.15 IR0= 816.78
MODEL0: IR0=816.780000 ACCURACY=0.620314 SUMIRP=11880.370000
MODEL1: IR1=-5329.251000 ACCURACY=0.546312 SUMIRN=-16392.841000
SUMIR:-4512.471000
最后的结果还是挺好的,8倍的收益,4000条测试数据,从2015年6月15日后一直到今天
训练数据有10多只股票的,是我随机挑选的,大概有51000条训练样本,训练时间大概有10分钟左右。召回率62%
前景展望:这个模型目前还需要大量测试,尤其是同一板块的数据集合起来进行训练,应该会有几十万个训练样本,线性分类器能否经得住考验还需要检验,此外还需要测试一下这个模型在牛市的表现。由于股价与成交量的非线性关系,探索非线性的若分类器应该理论上会提高分类精度,尤其是BP神经网络。