目录
1.前言
2.准备工作
(1)题目分析:
提供的数据集
问题
3.解题思路:
(1)第一问解题思路
4.代码实现
(1)第一题部分代码
之前和男朋友一起学完了数据挖掘的相关框架,决定要找一些题目来实战,偶然之下发现了这个比赛,于是在官网上找到了第一届比赛的赛题。本来想做B题的,但是B题是属于开放式数据集题目,为了更好的练习如何处理随机的原始数据集,所以,在商讨之后决定拿A题来作为练习题。
由于是第一次接触金融数据,也是学数据挖掘以来的第一次实战,所以,如果有错误的地方,请大家赐教,多多包含。那么就让我们开始吧!
题目压缩包可以在我的百度网盘上进行下载:
链接:https://pan.baidu.com/s/1AN2NP1_w_i72bC_vtNU2qw?pwd=bxx3
提取码:bxx3
题目中给我们提供了两个数据文件,分别是30支股票从2011年到2020年的行情数据,以及大湾区2011年到2020年的大湾区指数行情数据。
可以看到数据提供了股票代码(code)、当日开盘价格(open)、当日最高交易价格(high)、当日最低交易价格(low)、当日收盘价格(close)、当日交易量(volume)、当日交易额(amount) 的数据。
(30支股票数据与大湾区行情给出的数据类型相同)
问题剖析:
概括:题目中一公司给出了一种投资策略,即每周在30支股票中选取10支强势股票来进行投资,且每周一换仓(即卖出所有股票再买入上一周的强势股票)。
要求:将周一的收盘价格(close)作为准考虑收益,每只股票投资额固定为本金10%,手续费按万分之2.5计算。
第一小题:计算该投资策略的收益率曲线,并与大湾区指数
第二小题:调仓时间不变,调整单支股票投资额,找到最优的投资策略并绘制收益率曲线
第三小题:调仓时间不变,单只股票投资额定为本金10%,根据市场数据建模,得出自己的投资策略。
第四小题:调仓时间和投资额灵活变化,根据市场数据建模,得出自己的投资策略。(3个工作日完成建仓,仓位不低于50%,单支股票不超过总资产10%)
先做了第一、二题的分析,经过讨论,大致解题思路出来了(PS:打比赛队伍之内的讨论真的非常重要)
首先,我们需要搞清楚一个金融概念——收益率。
经过查找资料,我们知道收益率公式为:
收益率=收益额/原始投资额
又由于题目要求,将周一的收盘价格(close)作为准考虑收益,每只股票投资额固定为本金10%,手续费按万分之2.5计算。所以我们暂时将收益率公式抽象为以下代码:
price = open - open * (0.000025) #单支投资额
interest = ((close-open)/price ) * 100 # 利益率
这个时候,我的队友突然问了一个问题——本金怎么算,在经过商量之后,我们决定将本金定为10万。
为什么不可以直接将建仓时10支单股股票的总购买价定为本金呢?因为观察发现这30支股票的开盘价格从25元到110元左右不等,如果将10支单股股票的总购买价,若建仓时十支股票价格都是20-30元,那么第二周需要购买另10支股票时,可能会出现本金不够,无法购买的情况。为了避免这种情况出现,我们索性将本金定为10万,再根据要求将每支股票投资额定为本金的10%(即每支股票原始投资额为1万)。
这样一来,本金的问题就解决了。最终利益率抽象后公式为:
'''
power是单支股票的总收益额
price是购买单支股票的总入手价格
Interest是收益率
stocnum是本金能够购买的单支股票股数
principal是本金
'''
principal=100000
stocnum = int((principal / 10) / opendata[i])
power = (opendata1[i] - opendata[i]) * stocnum
price = (stocnum * opendata[i]) - (stocnum * opendata[i]) * (0.000025)
Interest = (sum(powerdata) / sum(pricedata)) * 100
在解决收益率的计算方法之后,后面的讨论基本都非常顺畅。
思路如下:
(1)3个工作日建仓:通过计算3天中第三天的收盘价格减去第一天的开盘价格作为收益,选取收益最高的10支股票用于建仓
(2)将30支股票数据剥离出来并另外保存:读取30支股票行情数据的,并对其进行切片,将30支股票从原始csv文件中分离出来并保存,方便后期读取
(3)将每周周一的收盘价和开盘价数据进行截取:由于我们需要利用每周一的收盘价和开盘价来计算每周的收益率,并由此决定下一周需要投资的10支强势股票,所以可以先将股票数据以每周作为阶段进行切片,再通过iloc方法将数据中每周的数据截取其中周一的close和open,将每周30支股票的周一数据拿出来。
(4)计算每周的强势股票:创建一个函数,调用(3)中函数,获取当周的30支股票周一收盘价和开盘价数据,用于计算当周每支股票的收益率,选取收益率最高的10支作为强势股票,作为下一周数据的投资股票,返回值为每周的强势股票股代码。在主函数中循环该函数,可以得到每周的强势股票数据。
(5)计算每周投资的利益率:创建一个函数,将(3)中数据和(4)中数据加入,将每周10支强势股票的股票代码与30支股票的周一数据进行键值匹配,得到每周10支股票周一的数据,用于计算每周的10支股票数据的利益率。
(6)用利益率数组绘制折线图:其中横坐标是年份(2011-2020)
分离30支股票数据,并保存:
import pandas as pd
# 读取数据并进行初步处理
def read_csv_shuju(path):
'''
:param path:
path:文件路径
:return:
data2: 处理后数据
'''
data1 = pd.read_csv(path, sep=',')
data1['date'] = pd.to_datetime(data1['time'])
data1['date']=data1['date'].dt.date
data2 = data1.drop([ 'time','volume', 'amount', 'open_interest'], axis=1)
data2.set_index('code', inplace=True)
states = ['date','open', 'hight', 'low', 'close']
data2.reindex(columns=states)
return data2
# 对数据进行分割并保存
def write_csv_data(data,start,code):
'''
:param:
data:需要分割的原始数据
start:上一次调用所到数据(每次输入时需要修改start的值为上一次输出的end值)
code:输入需要分割的数据的股票名称
:return: 根据输入的股票名称截取股票数据所在的列范围数据
'''
stock_code=[]
end=0
end+=start
for i in range(end,len(data.index)):
if data.index[i] == code:
end+=1
else:
continue
stock_code=data[start:end]
return end,stock_code
if __name__ == '__main__':
'''
stock_data为读取后初步处理数据(未分割)
stock_code为对数据按照股票代码进行分割后数据
'''
# 文件路径
path1 = '../data/附录一:30支股票行情.csv'
stock_data = read_csv_shuju(path1)
print("初步处理数据:")
print(stock_data)
# print(len(stock_data.index))
# print(stock_data.index[69696])
'''
# 这里需要手动修改参数,依次分割30支股票
需要修改的参数:
start: 修改为上一次输出的end值
code: 修改为需要分割出来的股票代码
文件名: 存入csv时的路径文件名
'''
end=0
start=67431
code='szse.000028'
stock_code=[]
end,stock_code=write_csv_data(stock_data,start,code)
# stock_code.to_csv('./code_data/30.csv')
print('分割后股票数据:')
print(stock_code)
print(stock_code.index)
print('end:')
print(end)
建仓函数:
def Stock_position_building():
'''
size_code:30支股票的编号
first_data:存取读取30支股票的利润
data1:将其股票编号和利润变成一维数组
data2:将其股票利润排序
data3:选取前十支股票
data4:十支优势股票的收市
'''
size_code = ['002027','300014','002475','000636','002449','600183','000049','002138'
,'300115','600325','000069','600383','600048','001914','601318','600323'
,'002152','000921','002035','000651','002233','002060','002352','002511'
,'002303','002461','600872','600332','000513','000028']
first_data,first_close = first_cycle_csv()
first_close_df=pd.Series(data=first_close,index=size_code)
data1 = pd.Series(data=first_data,index=size_code)
data2 =data1.rank(method='average',ascending=False).sort_values()
data3 = data2[0:11]
data_x = first_close_df.loc[data3.index]
print(data_x)
return data_x
def first_cycle_csv():
"""
first_data:用于存储利益数据
path:用于地址(有循环)
cut-up:读取data的前2-4条数据
close:最后一天闭市的数据
open:最初开始的数据
"""
first_data = []
first_close = []
for i in range(1,31):
path = './data_process/code_data/'+str(i)+'.csv'
data1 = pd.read_csv(path,sep=',')
cut_up = data1.iloc[1:4]
open = cut_up.iloc[0,2]
close = cut_up.iloc[2,5]
profit = close - open
first_data.append(profit)
first_close.append(close)
return first_data,first_close
获取每周10支强势股票的数据:
def cycle_csv(a):
'''
param: a是切片开始日期
'''
date_data=shuzu().dt.date
power=[]
state = ['open','close','code']
open_data=[]
for i in range(1,31):
list_data2 = []
list2_data1=[]
path = './data_process/code_data/'+str(i)+'.csv'
data1 = pd.read_csv(path,sep=',')
data1.set_index(['date'],inplace=True)
data2 = date_data[a:a+7]
for j in data2:
j = str(j)
list_data2.append(j)
for k in data1.index:
k= str(k)
if k in list_data2:
list2_data1.append(k)
else:
continue
data_x =data1.loc[list2_data1,state]
open = data_x.iloc[0,0]
close = data_x.iloc[len(data_x.index)-1,1]
power_data= close - open
power.append(power_data)
open_data.append(open)
'''
size_code:30支股票的编号
first_data:存取读取30支股票的利润
data1:将其股票编号和利润变成一维数组
data2:将其股票利润排序
data3:选取前十支股票
'''
size_code = ['002027','300014','002475','000636','002449','600183','000049','002138'
,'300115','600325','000069','600383','600048','001914','601318','600323'
,'002152','000921','002035','000651','002233','002060','002352','002511'
,'002303','002461','600872','600332','000513','000028']
data_1 = pd.Series(data=power,index=size_code)
data_2 =data_1.rank(method='average',ascending=False).sort_values()
data_3 = data_2[0:10]
open_data2=pd.Series(data=open_data,index=size_code)
# print(open_data2)
# print(data_3)
return data_3,open_data2
计算利益率:
def interest_rate(a,principal,front_stock):
'''
param:
a是切片日期
principal是设置的本金
front_stock是上周的10支强势股票
'''
if a > 3584:
stockwinner, stockopen30 = cycle_csv(a)
opendata = stockopen30.loc[front_stock.index]
else:
stockwinner, stockopen30 = cycle_csv(a)
stockwinner2, stockopen30_2 = cycle_csv(a + 7)
opendata = stockopen30.loc[front_stock.index]
opendata1 = stockopen30_2.loc[front_stock.index]
# print(opendata)
# print(opendata1)
powerdata = [] # 用于保存利益
pricedata = [] # 用于保存购入价格
for i in range(10):
stocnum = int((principal / 10) / opendata[i])
# print(stocnum)
power = (opendata1[i] - opendata[i]) * stocnum
price = (stocnum * opendata[i]) - (stocnum * opendata[i]) * (0.000025)
powerdata.append(power)
pricedata.append(price)
# allprice.append(sum(pricedata))
# allpower.append(sum(powerdata))
Interest = (sum(powerdata) / sum(pricedata)) * 100
# print(Interest)
return Interest