3基于机器学习的简单交易策略
至此,小瓦已经对KNN分类和回归模型有了基本的了解。当然除了KNN之外,还有很多算法可以供我们进行选择,如决策树、支持向量机、线性回归、逻辑回归等。接下来我们就使用最简单的KNN算法,基于真实的股票数据集来制订交易策略,并计算它所带来的收益。
1获取股票数据
首先我们使用之前学过的tushare来获取股票数据,这里需要导入一些必要的库,输入代码如下:
#导入Pandas
import pandas as pd
#导入金融数据获取模块tushare
import tushare as ts
#导入numpy,一会儿会用到
import numpy as np
#首先导入鸢尾花数据载入工具
from sklearn.datasets import load_iris
#导入KNN分类模型
from sklearn.neighbors import KNeighborsClassifier
#为了方便可视化,我们再导入matplotlib和seaborn
import matplotlib.pyplot as plt
import seaborn as sns
# 导入数据集拆分工具
from sklearn.model_selection import train_test_split
pd.set_option("expand_frame_repr", False) # True就是可以换行显示。设置成False的时候不允许换行
pd.set_option("display.max_columns", None) # 显示所有列
pd.set_option("display.max_rows", None) # 显示所有行
pd.set_option("colheader_justify", "centre") # 显示居中
运行代码,如果程序没有报错,就说明导入成功。接下来,我们可以定义一个获取股票数据的函数,以便未来还可以复用。输入代码如下:
# 首先我们来定义一个函数,用来获取数据
# 传入的参数分别是股票代码,开始时间、结束时间
def load_stock(ts_code, start, end):
ts.set_token("你的token")
pro = ts.pro_api()
df = pro.daily(ts_code=ts_code, start_date=start, end_date=end)
df.sort_values("trade_date", inplace=True)
df.set_index("trade_date", inplace=True)
return df
zgpa = load_stock(ts_code="002624.SZ", start="19900101", end="20230310")
zgpa.tail()
#设置token
s.set_token("你的token")
需要去tushare官网注册账户,就有了你的token,登录后个人主页中找
2创建交易条件
接下来我们做一点简单的特征工程,以便进行后面的工作。这里用每日开盘价减去收盘价,并保存为一个新的特征;用最高价减去最低价,保存成另外一个特征。如果股票次日收盘价高于当日收盘价,则标记为代表次日股票价格上涨;反之,如果次日收盘价低于当日收盘价,则标记为-代表股票次日价格下跌或者不变。这个过程可以称为创建股票的交易条件。
输入代码如下:
# 下面我们来定义一个用于分类的函数,给数据表增加三个字段
# 首先是开盘价减去收盘价,命名为open-close
# 其次是最高价减去最低价,命名为high-low
def classification_tc(df):
df["open-close"] = df["open"] - df["close"]
df["high-low"] = df["high"] - df["low"]
# 添加一个target字段,如果次日收盘价高于当日收盘价,则标记为1,反之为-1
df["target"] = np.where(df["close"].shift(-1)>df["close"], 1, -1)
# 去掉有空值的行
df =df.dropna()
# print(df.tail(9))
# 将open-close和high-low作为数据集的特征
X = df[["open-close", "high-low"]]
# 将target值给y
y = df["target"]
return(X, y)
# x,y=classification_tc(zgpa)
# print(x.tail())
# print(y.tail())
运行代码,就完成了这个函数的定义。由于我们通过股票价格变化的情况对数据进行了分类,即1代表价格上涨,–1代表价格下跌或不变,这个交易条件可以用来训练分类模型。让模型预测某只股票在下一个交易日价格上涨与否。
如果要创建用于回归模型的交易条件,则可以对代码稍做调整,将次日收盘价减去当日收盘价的差作为预测的目标。这样就可以训练回归模型,使其预测次日股价上涨的幅度。输入代码如下:
# 下面定义一个用于回归的函数
# 特征的添加与分类函数类似
# 只不过target字段改为次日收盘价减去当日收盘价
def regression_tc(df):
df["open-close"] = df["open"] - df["close"]
df["high-low"] = df["high"] - df["low"]
# 添加一个target字段,如果次日收盘价高于当日收盘价,则标记为1,反之为-1
df["target"] = df["close"].shift(-1) - df["close"]
# 去掉有空值的行
df =df.dropna()
# print(df.tail(9))
# 将open-close和high-low作为数据集的特征
X = df[["open-close", "high-low"]]
# 将target值给y
y = df["target"]
return(X, y)
x,y=regression_tc(zgpa)
print(x.tail())
print(y.tail())
运行代码即可完成回归交易条件函数的定义。与分类交易条件一样,我们同样是把股票当日的开盘价和收盘价的差,与最高价和最低价的差作为样本的特征。不同的是,预测目标变成了次日收盘价与当日收盘价的差。
3使用分类算法制定交易策略
接下来,我们就使用上一步中定义的函数来处理下载好的股票数据,生成训练集与验证集,并训练一个简单的模型,以执行我们的交易策略。输入代码如下:
#使用classification_tc函数生成数据集的特征与目标
X, y = classification_tc(zgpa)
#将数据集拆分为训练集与验证集
X_train, X_test, y_train, y_test =
train_test_split(X, y, train_size=0.8)
运行代码后,我们会得到训练集与预测集。现在就使用KNN算法来进行模型的训练,并查看模型的性能。输入代码如下:
#创建一个KNN实例,n_neighbors取95
knn_clf = KNeighborsClassifier(n_neighbors=95)
#使用KNN拟合训练集
knn_clf.fit(X_train, y_train)
#输出模型在训练集中的准确率
print(knn_clf.score(X_train, y_train))
#输出模型在验证集中的准确率
print(knn_clf.score(X_test, y_test))
【结果分析】从代码运行结果可以看到,使用经处理的数据集训练的KNN模型,在训练集中的准确率是54%左右,在验证集中的准确率也是51%左右。这个准确率远谈不上理想,相当于只有一半时间里模型对股价的涨跌预测正确。原因是我们训练模型的样本特征确实太少了,无法支撑模型做出正确的判断。不过大家也不要担心,我们只是初步做一个演示而已。
既然模型已经可以做出预测,接下来我们就可以来验证一下,使用模型预测作为交易信号来进行交易,并且与基准收益进行对比。首先我们要计算出基准收益和基于模型预测的策略所带来的收益。输入代码如下:
#使用KNN模型预测每日股票的涨跌,保存为Predict_Signal
zgpa["predict_signal"] = knn_clf.predict(X)
#在数据集中添加一个字段,用当日收盘价除以前一日收盘价,并取其自然对数
zgpa["return"] = np.log(zgpa["close"]/zgpa["close"].shift(1))
#查看一下
zgpa.tail()
【结果分析】从输出中可以看到,数据表中的Predict_Signal存储的是KNN模型对股票涨跌的预测,而Return是指当日股票价格变动所带来的收益。下面我们定义一个函数,计算一下累计的基准收益。输入代码如下:
# 定义一个计算累计基准收益的函数
def cum_return(df, split_value):
# 该股票基准收益的总和乘以100,这里只计算预测集的结果
cum_returns = df[split_value:]["return"].cumsum()*100
# 将计算结果进行返回
return cum_returns
运行代码,就完成了这个函数的定义。接下来我们再定义一个函数,计算基于KNN模型预测的交易信号所进行的策略交易带来的收益。输入代码如下:
# 定义一个计算使用策略交易的收益
def stratrgy_return(df, split_value):
# 使用策略交易的收益为模型乘以模型预测的涨跌幅
df["stratrgy_return"] = df["return"] * df["predict_signal"].shift(1)
# 将每日策略交易的收益加和并乘以100
cum_strategy_return = df[split_value:]["stratrgy_return"].cumsum()*100
return cum_strategy_return
定义完上面的函数之后,我们就可以很快计算出算法模型所带来的累计收益了。为了方便对比,我们再来定义一个进行可视化的函数,输入代码如下:
# 定义一个绘图函数,用于对比基准收益和算法交易的收益
def plot_chart(cum_return, cum_strategy_return, symbol):
plt.figure(figsize=(9,6))
plt.plot(cum_return, "--", label="%s Returns"%symbol)
plt.plot(cum_strategy_return, label="StrategyReturns")
plt.legend()
plt.show()
绘函数定义好之后,我们就可以对KNN模型带来的策略收益和基准收益进行对比了。输入代码如下:
cum_return = cum_return(zgpa, split_value=len(X_train))
cum_strategy_return = stratrgy_return(zgpa, split_value=len(X_train))
plot_chart(cum_return, cum_strategy_return, "zgpa")
【结果分析】从输出中可以看到,虚线部分是该股票的累积基准收益,实线部分是使用算法进行交易的累计收益。虽然这里使用的KNN分类模型的准确率并不高,但是使用该模型进行涨跌预测后,进行交易的收益还是高于该股票的基准收益的。如果我们通过补充因子的方法来进一步提高模型的准确率的话,则算法交易带来的收益还会显著提高。注意:与第2章所使用的回测方式不同,这里我们通过对算法交易收益与基准收益的对比来评估策略的业绩,而这种方法在实际应用中更加普遍。
4小结
在本章中,小瓦提出一个非常不错的想法——使用机器学习算法来预测股票的涨跌,并据此创建交易策略来执行订单,因此我们和小瓦一起学习了机器学习的基本概念,并以KNN算法为例,展示了机器学习工具的使用方法。由于本章中用来训练模型的样本数据维度比较少,模型的性能表现也就谈不上出色。即便如此,基于KNN算法设计的交易策略,收益率仍然明显领先基准收益。在第4章中,我们就要研究如何补充数据维度,进一步提升模型的性能。
文章为作者独立观点,不代表 股票程序化软件自动交易接口观点