「量化交易」基于sklearn包的支持向量机个股择时策略

支持向量机(Support Vector Machine)

支持向量机是很好用分类工具,利用股票的历史数据,可以以股票前一日的指标作为特征;当日的涨跌作为标记。训练出一个具有对当天股票走势有一定预测能力的分类器,从而进行相应的买入、卖出或是观望操作。

 

择时策略

在sklearn包提供的SVM算法基础上,我设计了一个个股择时策略。

首先获取个股历史数据,计算每一天个股的前日MOM、WMA、SMA指标(30日),并保存起来作为训练特征,然后用昨日的股价减去今日的股价,得到涨跌情况,作为对应的标记。

接着将训练集放进SVM进行训练。

上面都是预处理部分,进入每日回测,只需要计算前日的MOM、WMA和SMA指标(30日),然后使用训练好的SVM分类器预测一下结果,如果预测股票涨那就买,如果预测股票跌那就卖出。

 

效益分析

以下回测分析基于JoinQuaint的股票数据。

创业环保(600874)

先以创业环保个股作为例子,策略的回测时间是从2016年1月1日到2017年的七月。

接下来我尝试了以上证指数(000001.XSHG)作为训练集,特征仍然用90十日的SMA、MOM、WMA指标。

可以看出,虽然基于个股本身,能带来一定收益,但是该股基于大盘却没有发出卖信号。之后换了多支不同的个股进行测试发现,不管是上证指数还是沪深300作为训练数据集也是这个效果,可见SVM这个方法的确存在一定局限性。

西藏天路(600326)

多次选股实验之后,发现这只股票使用SVM进行预测效果还比较好,策略参数和上一支股有一点不同:训练数据量由2400个交易日缩小了600个交易日。当然这么做是因为能让效益更高。

 

策略总结

除了上面这三个作为例子的个股之外,我还测试了其他的个股。令我记忆较深的是,例如中国石油、中国中铁或者各类银行股,他们采用SVM的方法进行股票买卖点预测,均发出了很少的买信号。

而对于一些波动比较大的股,例如上文的西藏天路等,就发出了不少的买信号。

这可能是SVM中参数细节的设置,但是SVM算法源于一个第三方库,而不是自己实现的,所以说还不能在很好地进行细节调参。

至于SVM方法本身,不像技术面指标,大部分拥有默认的参数。SVM没有默认的参数,针对不同的股票相同参数可能效益相差大,而且即使最佳调参,对部分股票的效果也仍然比较差。

此外,本方法目前还不能用大盘作为模型训练集来预测,所以虽然对一些股票能带来较好收益,但是我的这个思路仍然是一个不成熟的方法,具体改善方法我认为会在经济学或者数学上得到解答。

 

策略代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
import talib
from jqdata import *
import numpy
from sklearn import svm
 
'''
================================================================================
总体回测前
================================================================================
'''
#总体回测前要做的事情
def initialize(context):
    set_params(context)    #1设置策参数
    set_variables() #2设置中间变量
    set_backtest()  #3设置回测条件
 
#1
#设置策略参数
def set_params(context):
    g.security = '600874.XSHG' # 买卖股
    #g.benchmark = '000001.XSHG' # 训练股是大盘
    g.benchmark = g.security # 训练股是买卖股本身
    SVM_train(context)
    set_benchmark(g.security) # 设置基准收益
 
 
#2
#设置中间变量
def set_variables():
    return
 
#3
#设置回测条件
def set_backtest():
    set_option('use_real_price', True) #用真实价格交易
    log.set_level('order', 'error')
 
# SVM训练分类器
def SVM_train(context):
    end_date = context.previous_date # 结束时间为回测的开始时间的前一天
 
    trading_days = get_all_trade_days().tolist()
    end_date_index = trading_days.index(end_date)
    start_date_index = end_date_index - (200 * 12)   # 周期为 200*12 个交易日的数据用于训练
 
    x_train = []    # 特征
    y_train = []    # 标记
 
    # 计算指标作为特征,并自动标记
    for index in range(start_date_index, end_date_index):
 
        start_day = trading_days[index - 90] # 指标的计算范围为90个交易日
        end_day = trading_days[index]
        stock_data = get_price(g.benchmark, start_date=start_day, end_date=end_day, frequency='daily', fields=['close', 'volume']) # 获得前三十天的收盘价
        close_prices = stock_data['close'].values # 将收盘价提取出来
        volume = stock_data['volume'].values
 
        #通过三十天收盘价计算指标
        sma_data = talib.SMA(close_prices)[-1]
        wma_data = talib.WMA(close_prices)[-1]
        mom_data = talib.MOM(close_prices)[-1]
 
        features = []
        features.append(sma_data)
        features.append(wma_data)
        features.append(mom_data)
 
        label = False # 标记为跌(False)
        if close_prices[-1] > close_prices[-2]: # 如果今天的收盘价超过了昨天,那么标记为涨(True)
            label = True
        x_train.append(features)
        y_train.append(label)
 
    g.svm_module = svm.SVC()
    g.svm_module.fit(x_train, y_train) # 训练分类器
 
 
'''
================================================================================
每天交易时
================================================================================
'''
def handle_data(context, data):
    dt = context.previous_date
    trading_days = get_all_trade_days().tolist()
    index = trading_days.index(dt)
    today_stock_data = get_price(g.security, start_date=trading_days[index-90], end_date=trading_days[index], frequency='daily', fields=['close', 'volume'])
    close_prices = today_stock_data['close'].values
    volume = today_stock_data['volume'].values
 
    # 计算指标
    sma_data = talib.SMA(close_prices)[-1]
    wma_data = talib.WMA(close_prices)[-1]
    mom_data = talib.MOM(close_prices)[-1]
 
    #添加今日的特征
    features = []
    x = []
    features.append(sma_data)
    features.append(wma_data)
    features.append(mom_data)
    x.append(features)
 
    flag = g.svm_module.predict(x[-1]) # 预测的涨跌结果
 
    cash = context.portfolio.portfolio_value
    if flag == True:
        if cash > 0:
            #买入
            order_target_value(g.security, cash)
            print ("时间:%d/%d/%d    操作:买入    当前股价:%f"%(dt.year, dt.month, dt.day, data[g.security].price))
    else:
        #卖出
        order_target_value(g.security, 0)
        print ("时间:%d/%d/%d    操作:卖出    当前股价:%f"%(dt.year, dt.month, dt.day, data[g.security].price))