用机器学习方法构建量化策略

1、机器学习与量化投资简介

1.1机器学习方法简介

机器学习方法是一系列用于使计算机系统能够从数据中学习的算法和技术的统称。这些方法的主要目标是让机器能够自动地识别模式、进行预测或做出决策,而无需进行明确的编程。

机器学习方法可以分为几大类,包括监督学习、非监督学习、半监督学习和强化学习等。

监督学习:这是机器学习中最为常见的一类方法。在监督学习中,模型使用带有标签(或结果)的训练数据进行学习。标签通常是人工提供的,用于指导模型如何做出预测。通过不断地比较模型的预测结果与实际标签,模型会逐步调整其内部参数,以最小化预测误差。监督学习通常用于分类(如垃圾邮件识别、手写数字识别等)和回归(如房价预测、股票价格预测等)问题。
非监督学习:与监督学习不同,非监督学习使用的数据没有明确的标签。模型需要自行发现数据中的内在结构或模式。常见的非监督学习方法包括聚类(将数据分组为具有相似特征的簇)和降维(简化数据的复杂性以便更好地进行分析)。

半监督学习:这种方法结合了监督学习和非监督学习的特点。在半监督学习中,部分数据带有标签,而部分数据则没有。模型利用带标签的数据进行训练,并尝试从未标记的数据中提取有用的信息。
强化学习:强化学习是一种通过与环境交互来学习的方法。在这种方法中,模型(或称为智能体)通过尝试不同的行为并观察结果来进行学习。模型的目标是最大化一个奖励函数,该函数会根据模型的行为返回奖励或惩罚。强化学习常用于机器人控制、游戏AI等领域。

此外,还有一些其他的机器学习方法,如集成学习(将多个模型的预测结果结合起来以提高性能)、深度学习(使用神经网络模型进行特征提取和预测)等。

机器学习有四种用途:分类、聚类、回归和降维。更简单一点,机器学习的目的只有三个:分类、聚类和回归,降维只是达成目标的手段之一。
所以别看各种算法、模型花里胡哨,最终的目的还是完成这几个任务目的。

机器学习工作流(WorkFlow)包含数据预处理(Processing)、模型学习(Learning)、模型评估(Evaluation)、新样本预测(Prediction)几个步骤。
数据预处理:输入(未处理的数据 + 标签)→处理过程(特征处理+幅度缩放、特征选择、维度约减、采样)→输出(测试集 + 训练集)。
模型学习:模型选择、交叉验证、结果评估、超参选择。
模型评估:了解模型对于数据集测试的得分。
新样本预测:预测测试集。
关于机器学习,和鲸社区有很多项目,各位可以自行学习研究,这里受限于篇幅,只能点到为止。

1.2机器学习应用量化投资

机器学习在量化投资领域的应用逐渐广泛,用以指导投资决策。
应用方向:
数据挖掘与特征提取:量化投资的核心在于数据分析,而机器学习可以有效地从海量数据中挖掘出有价值的信息。通过对股票交易价格、公司业绩、市场情绪等多维度数据的分析,机器学习算法能够识别出影响股市变化的隐藏因素,并据此构建预测模型。
预测模型构建:机器学习算法可以构建预测模型,用于预测股票价格走势、最佳投资组合、最佳买入卖出时机等。这些模型通过对历史数据的训练,不断优化自身的预测能力,帮助投资者做出更明智的投资决策。
风险控制:在量化投资中,风险控制至关重要。机器学习可以构建风险管理系统,通过对市场行为的实时监测,及时发现潜在风险并采取相应的风险控制措施。这有助于投资者在保持收益的同时,降低投资风险。

当然使用机器学习进行量化投资还需要注意以下几点:
数据质量:机器学习模型的性能很大程度上取决于输入数据的质量。因此,投资者需要确保所使用的数据准确、完整且具有代表性。
模型选择与优化:不同的机器学习算法适用于不同的场景和数据类型。投资者需要根据实际情况选择合适的算法,并通过不断调整参数来优化模型的性能。
结合投资经验:机器学习模型虽然强大,但并不能完全替代投资者的经验和判断。在实际操作中,投资者应将模型的预测结果与自己的投资经验相结合,以做出更合理的投资决策。

后续章节,我们将结合机器学习进行量化投资的研究及分析。

2、在量化投资上的应用

2.1K最近邻算法

K最近邻(K-Nearest Neighbors,简称KNN)是一种常用的监督学习算法,主要用于分类和回归问题。KNN的基本原理是基于特征空间中样本点的距离来进行预测或分类。
对于分类问题,KNN找到与待分类样本在特征空间中最近的K个训练样本,并基于它们的类别标签进行投票决策。对于回归问题,KNN找到最近的K个训练样本,并计算它们的平均值或加权平均值来预测待预测样本的数值输出。我们看个案例

#导入相关库,为了避免重复,这里一次性导入本内容所需要的所有库
import pandas as pd 
import numpy as np      
import matplotlib.pyplot as plt
import akshare as ak
import warnings
import backtrader as bt
import datetime
import statsmodels.api as sm
warnings.filterwarnings('ignore')
plt.rcParams['font.sans-serif'] = ['Source Han Sans CN']#和鲸平台可用的中文字体
plt.rcParams['axes.unicode_minus'] = False





from sklearn import datasets  
from sklearn.neighbors import KNeighborsClassifier  
from sklearn.model_selection import train_test_split 
# 加载鸢尾花数据集  
iris = datasets.load_iris()



# 将数据转化为pandas DataFrame  
df_iris = pd.DataFrame(data=iris.data, columns=iris.feature_names)  
  
# 添加目标列  
df_iris['target'] = iris.target  
  
# 将目标列中的数字标签替换为实际的类别名称  
df_iris['target'] = df_iris['target'] 
  
# 显示DataFrame的前几行  
df_iris.head()




#进行训练
X = iris.data  
y = iris.target  
  
# 划分训练集和测试集  
X_train, X_test, y_train, y_test = train_test_split(X, y)  
  

# 创建KNN分类器实例,设置邻居数量为3  
knn = KNeighborsClassifier(n_neighbors=3)  
  
# 使用训练集对KNN分类器进行训练  
knn.fit(X_train,y_train)  
   
  
# 输出分类准确率 
print('训练集准确率',knn.score(X_train,y_train))  
print('测试集准确率',knn.score(X_test,y_test))



从结果来说,95%的准确率已经非常好了,但是这个案例只是简单地演示了如何使用KNN算法,实际应用中,还需要进一步的优化和调整。
可以通过不同的参数来调整KNN算法的性能,这就涉及到网格搜索参数了,例如邻居数量(n_neighbors)、距离度量(metric)等。同时,还可以使用不同的数据集和特征来评估算法的效果。

2.2用于股票金融

knn不仅可以用于分类,也可以用于回归。在回归任务中,KNN通过查找与给定样本最相似的K个邻居,并根据这些邻居的因变量值的平均值来预测未知样本的因变量值。
到这我们可以初步形成一个思路,即利用原始数据构建特征,然后使用KNN算法进行分类或回归预测。

df=pd.read_excel(r'/home/mw/input/000018533/QF_6_000300sh.xlsx')#导入数据
df=df.set_index(pd.to_datetime(df['日期'].astype('str'))).sort_index()
df




#构建特征
df['收盘涨跌幅']=df['close'].pct_change()
df['开盘涨跌幅']=df['open']/df['close'].shift(1)-1
df['当日振幅']=(df['high']-df['low'])/df['close'].shift(1)
df['signal']=np.where(df['close'].shift(-1)>df['close'],1,-1)
df.dropna(inplace=True)




#数据分类
X = df.loc[:,['ADRCALL', 'ADRPUT','收盘涨跌幅', '开盘涨跌幅', '当日振幅']].values
y = df.signal.values
# 划分训练集和测试集  
X_train, X_test, y_train, y_test = train_test_split(X, y)




# 创建KNN分类器实例,设置邻居数量为3
knn = KNeighborsClassifier(n_neighbors=3)  
  
# 使用训练集对KNN分类器进行训练  
knn.fit(X_train,y_train)  
   
  
# 输出分类准确率 
print('训练集准确率',knn.score(X_train,y_train))  
print('测试集准确率',knn.score(X_test,y_test))




#我们看下历史预测结果
df['predict_signal']= knn.predict(X)
df

测试成绩略只能说过得去,假设当前['ADRCALL', 'ADRPUT','收盘涨跌幅', '开盘涨跌幅', '当日振幅']
特征值为 [6,284,-0.02451,-0.000995,0.0225],预测未来一天上涨或下跌?

knn.predict([[6,284,-0.02451,-0.000995,0.0225]])

2.3聚类算法

聚类算法是一种无监督学习方法,旨在将数据集划分为若干个互不相交的子集,这些子集被称为簇。每个簇中的数据尽可能相似,而不同簇之间的数据则尽可能不同。聚类算法广泛应用于各种领域,包括图像处理、模式识别、市场分析、生物信息学等。而在金融市场上,通过将股票数据划分为不同的簇,可以发现股票市场中具有相同特征个体,并据此制定投资策略。
我们先看看聚类算法的案例

from sklearn.cluster import KMeans  
 
# 假设我们有一个二维数据集  
data = np.random.rand(100,2) 
  
# 创建KMeans实例,设定簇的数量为3  
kmeans = KMeans(n_clusters=3, random_state=0)  
  
# 对数据进行拟合  
kmeans.fit(data)  
  
# 获取聚类标签和质心  
labels = kmeans.labels_  
centroids = kmeans.cluster_centers_  
  
# 可视化结果  
plt.scatter(data[:, 0], data[:, 1], c=labels, cmap='viridis')  
plt.scatter(centroids[:, 0], centroids[:, 1], c='red', s=300, alpha=0.5)  
plt.show()

2.4聚类应用

聚类算法可以用于金融市场的股票分类。通过将股票数据划分为不同的簇,可以发现股票市场中具有相同特征的股票,并据此制定投资策略。例如,可以将股票数据根据其特征(如市值、收益率、波动性等)划分为不同的簇,然后根据每个簇的特征选择相应的股票进行投资。

df_a=pd.read_csv(r'/home/mw/input/01a7320/教案所需数据.csv',index_col=0)#导入数据
df_a.index=pd.to_datetime(df_a.index)
df_a.sort_index(inplace=True)




#这里面是日线数据,一般基本面因子是以周/月为周期进行测试,所以我们还要调整一下,只保留每个月最后一天的数据。
stock_count=pd.DataFrame(columns=['ts_code', 'trade_date', 'turnover_rate', 'turnover_rate_f',
       'volume_ratio', 'pe', 'pe_ttm', 'pb', 'ps', 'ps_ttm', 'dv_ratio',
       'dv_ttm', 'total_share', 'float_share', 'free_share', 'total_mv',
       'circ_mv', 'close.1', 'vol'])
for a,b in df_a.groupby('ts_code'):
    b.sort_index(inplace=True)
    stock_count_1=b.resample('M').last()
    stock_count=pd.concat([stock_count,stock_count_1])
stock_count.sort_index(inplace=True)
stock_count['trade_date']=stock_count.index




stock_count_data=stock_count['2022-11'].set_index('ts_code')
stock_count_data12=stock_count['2022-12'].set_index('ts_code')
stock_count_data['T+1收益率']=stock_count_data12['close.1']/stock_count_data['close.1']-1
stock_count_data.dropna(inplace=True)





#我们选取pe	pe_ttm	pb	ps	ps_ttm	等指标进行均值分类,并给相应股票打上标签
from sklearn.cluster import KMeans 
# 创建KMeans实例,设定簇的数量为4 
kmeans = KMeans(n_clusters=5, random_state=0)  
kmeans_data=stock_count_data.loc[:,['pe', 'pe_ttm', 'pb', 'ps', 'ps_ttm']].values 
# 对数据进行拟合  
kmeans.fit(kmeans_data)





# 获取聚类标签
labels = kmeans.labels_  
stock_count_data['labels']=labels
stock_count_data




#接下来可以分别标签不同的个股,计算次月平均收益率。
stock={}
for i,g in stock_count_data.groupby('labels'):
    stock[i]=g['T+1收益率'].mean()
stock#查看不同标签下面次月收益

2.5本节小结:

受限于篇幅,本节只讲解了几个算法在量化上面的应用,看过之后各位会发现其实很简单,因为机器学习这门技术本身就是个工具,重点在于你需要用到什么!
说直接点,你的思路比起算法更重要!只有知道自己要做什么,才能拿起机器学习这把锤子,去锤你想要的东西!

2.6本节练习

请你尝试用聚类算法,对股票进行聚类(营收同比,利润同比等财务指标,需要自己获取),并计算次月收益率。

3、基于机器学习构建量化策略。

3.1利用最近邻机器算法构建指标

from sklearn.neighbors import NearestNeighbors
#第一步,计算相关指标
# 计算快速和慢速ADR指标
ADR_quick = df['ADRCALL'].rolling(5).mean().dropna()#快速指标,5日均值
ADR_slow = df['ADRCALL'].rolling(20).mean().dropna()#慢速指标,20日均值




#第二步,整理数据
#合并成为一个dataframe
data = pd.concat([df.close, ADR_quick, ADR_slow ], axis=1)
data.columns = ['close', 'ADR_quick', 'ADR_slow']
#计算标签,1表示上涨,-1表示下跌
data['next_pct_change']=df.close.pct_change().shift(-1)#次日涨跌幅
data["label"] = (data.next_pct_change > 0).astype(int) *2 -1
data = data.dropna()#删除空值
#提取数值
ADR_quicks = data['ADR_quick']
ADR_slows = data['ADR_slow']
labels = data['label']




#第三步构建一个指标
# 创建一个空的结果序列
result = pd.Series(dtype='float64')
for i in range(200, len(data)):#100取值为间隔区间
    # 获取当前行的adr_quick和adr_slow值
    current_ADR_quicks = ADR_quicks.iloc[i]
    current_ADR_slows = ADR_slows.iloc[i]

    # 取出历史样本
    historical_ADR_quicks = ADR_quicks.iloc[:i]
    historical_ADR_slows = ADR_slows.iloc[:i]
    historical_labels = labels.iloc[:i]

    # 将ADR_quicks和ADR_slows值组合成一个特征向量
    features = np.column_stack((historical_ADR_quicks,historical_ADR_slows))

    # 使用K最近邻算法找到历史样本中最靠近的k个样本
    nn = NearestNeighbors(n_neighbors=10)#参数设为10
    nn.fit(features)
    _, indices = nn.kneighbors([[current_ADR_quicks,current_ADR_slows]])
    # 取出对应的label值,并计算均值
    closest_labels = historical_labels.iloc[indices[0]]
    mean_label = closest_labels.mean()
    print('第%s次训练,均值为%s'%(i,mean_label))
    # 将均值添加到结果序列中
    result = pd.concat([result, pd.Series(mean_label)], ignore_index=True)

result.index = data.iloc[200:].index

result = result.rolling(5).mean()



result.describe()



result.plot(figsize=(10,5))

这个指标的构建原理,说起来就两句话
1.寻找历史样本中与当前样本最接近的k个样本
2.计算这k个样本的次日的涨跌幅,上涨标记1,否则为0,记为label
3.计算这k个样本的label的均值,作为当前的label,越接近1表明上涨概率越大,通过走势判断未来上涨概率大,还是下跌概率大。

3.2基于机器学习构建量化策略。

df_03=df['2020':]
df_03['result']=result['2020':]
df_03



class PandasData_more(bt.feeds.PandasData):
    lines = ('result',) # 要添加的线
    # 设置 line 在数据源上的列位置
    params=(('result', -1),)
    # -1表示自动按列明匹配数据,也可以设置为线在数据源中列的位置索引 
cerebro = bt.Cerebro()
df_03['openinterest']=0#添加一列数据
df_03=df_03.loc[:,['open','high','low','close','vol','openinterest','日期','result']]#选择数据
df_03.columns=['open','high','low','close','volume','openinterest','datetime','result']#修改列名
data_=df_03.set_index(pd.to_datetime(df_03['datetime'].astype('str'))).sort_index()#排
data_.loc[:,['volume','openinterest']] = data_.loc[:,['volume','openinterest']].fillna(0)
data_.loc[:,['open','high','low','close']] = data_.loc[:,['open','high','low','close']].fillna(method='pad')    
datafeed = PandasData_more(dataname=data_,
                               fromdate=datetime.datetime(2020,1,1),
                               todate=datetime.datetime(2024,2,8)) 
cerebro.adddata(datafeed, name='000300.SH') # 通过 name 实现数据集与股票的一一对应





# 创建策略
class ADR_day(bt.Strategy):
    def __init__(self):
        print('回测开始')
    def next(self):
        #计算买卖条件
        #空仓时开多
        if self.getposition(self.data0).size==0:#空仓情况下
            self.num=0
            if self.data0.result[0]>0.22: #均值加一倍标准差
                self.order = self.order_target_percent(self.data0,0.99)
                print('时间:%s买入开仓成功'%self.datetime.date(0),self.data0.result[0])
        elif self.getposition(self.data0).size>0:#持有多单仓情况下
            if self.data0.result[0]<0: 
                self.order = self.order_target_percent(self.data0,0)
                print('时间:%s卖减多仓成功'%self.datetime.date(0),self.data0.result[0])

cerebro.addstrategy(ADR_day)
# 初始资金 1,000,000
cerebro.broker.setcash(10000000.0)
# 佣金,双边各 0.0003
cerebro.broker.setcommission(commission=0.0003)
# 滑点:双边各 0.0001
cerebro.broker.set_slippage_perc(perc=0.0001)


# 添加分析指标
# 返回年初至年末的年度收益率
cerebro.addanalyzer(bt.analyzers.AnnualReturn,_name='_AnnualReturn')
# 计算最大回撤相关指标
cerebro.addanalyzer(bt.analyzers.DrawDown,_name='_DrawDown')
# 计算年化收益
cerebro.addanalyzer(bt.analyzers.Returns,_name='_Returns',tann=252)
# 计算年化夏普比率
cerebro.addanalyzer(bt.analyzers.SharpeRatio_A,_name='_SharpeRatio_A')
# 返回收益率时
cerebro.addanalyzer(bt.analyzers.TimeReturn,_name='_TimeReturn')

# 启动回测
result=cerebro.run()#这里核心关键是设置cpu单核测试




#走势对比
ret = pd.Series(result[0].analyzers._TimeReturn.get_analysis())#获得收益时序图
#画图
fig, ax1 = plt.subplots(figsize=(10,6),dpi=100)#创建画布
ax1.plot((ret+1).cumprod().index,(ret+1).cumprod().values,'r-',label = "成分股涨跌比例策略走势")
ax1.plot((data['2020':].close.pct_change(1)+1).cumprod(),'b-',label = "沪深300走势")
ax1.set_title('成分股涨跌比例策略收益与沪深300指数对比',fontsize=10)
ax1.legend(loc='upper right')
plt.show()

3.3本节小结

本节我们通过机器学习的方法构建了一个指标,并且通过回测来验证了该指标是否有效。
虽然结果并不让人满意,但至少给我们打开了一个思路,即机器学习的方法可通过多种方式应用于量化投资,当然是否有效需要我们进一步的研究验证。

3.4本节动手题

本节自定义机器学习指标没有函数化,请你把构建指标的过程函数化,方便后期调用
此外,请你尝试优化参数或买卖条件,使得指标更有效。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值