1.研报概述

本文是研报复现系列的第一篇,文本复现了【方正证券】的研报【跟踪聪明钱:从分钟行情数据到选股因子】。

该研报尝试从分钟行情数据中挖掘出那些聪明人(即机构)所做的交易,称为“聪明钱”,并量化这些聪明钱对后市看涨、看跌的情绪观点,进而跟随聪明钱进行选股。

2.研究环境

JointQuant

import datetime
import math
import matplotlib.pyplot as plt
from jqdata import *
import pandas as pd
import numpy as np
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

3.研报复现

3.1 数据获取

本文数据来源于聚宽JoinQuant。用到的接口名和功能如下表所示。具体参数请查阅聚宽的API文档。

接口名 功能
get_bars 获取行情数据
get_price 获取获取数据、是否停牌、涨跌停价
get_trade_days 获取一段时间内的交易日列表
get_extras 查询特定股票是否是ST股
get_all_securities 获取股票数据,包括上市时间
get_index_stocks 获取指数成分股

3.2 划分聪明钱

聪明钱在交易过程中往往呈现“单笔订单数量更大、订单报价更为激进”

因此,某分钟的交易的聪明度指标S定义为:S=∣Rt∣\left| Rt \right|∣Rt∣///Vt\sqrt{Vt}Vt​。

Rt为第t分钟的涨跌幅,Vt为第t分钟的成交量。S的值越大,则说明此交易越聪明。

我们封装一个获取分钟行情数据以及S值的函数,方便后面的研究使用。

def get_minute_data(security,#股票代码,可以是list或者字符串count,#获取多少条数据end_dt=datetime.datetime.now()
):
df = get_bars(security,
count = count,
include_now=True,
unit = '1m',
fields = ['date','open','close','volume'],
df = True,
end_dt = end_dt)df['R'] = (df['close'] - df['open'])/df['open']#涨跌幅
df['S'] = abs(df['R'])/df['volume']**0.5*10000 #S值,乘10000为了方便画图
df['volume'] = df['volume']/10000#volume除以10000方便画图
return df

原研报利用成交量与计算出的S值来划分聪明钱交易。

划分算法为:
step1:对于特定股票,特定时间段的分钟级交易数据,计算得到每分钟的S值,并将数据按照S值由大到小排序。
step2:求排序后的分钟数据的交易量累加和,将交易量累加和占该该时间段总成交量前20%的分钟交易视为由聪明钱进行的交易。

其中,阈值选取20%是因为在A股市场中机构交易者只贡献了少量的交易量,原研报同时测试了阈值选取其他数值时效果,其中20%是最优的.

我们以603198.XSHG在2021年4月8日下午14:00到14:30的分钟数据为例,给出划分聪明钱的程序并将结果可视化。

'''
功能:寻找聪明钱的交易并可视化
算法:对于特定的股票,特定时间段的分钟级交易数据,计算得到每分钟的S值,并将数据按照S值由大到小排序。求排序后的分钟数据的交易量累加,将交易量累加和占比前20%的分钟视为由聪明钱交易的时刻。其中,阈值选取20%是因为在A股市场中机构交易者只贡献了少量的交易量,原研报同时测试了阈值选取其他数值时效果,其中20%是最优的。
数据:以603198.XSHG在2021年4月8日下午14:00到14:30的分钟数据为例。
'''
#获取数据并且个每个分钟编号
df = get_minute_data('603198.XSHG',30,end_dt='2021-04-08 14:30:00')
df['bar_no'] = [_ for _ in range(1,31)]#每根bar的序号,方便x轴的显示#绘图
fig = plt.figure(figsize=(14,10))
#S值与成交量图
ax = fig.add_subplot(211)
h1 = ax.bar(df.index,df['volume'],label='成交量',width=0.5)#成交量
ax2 = ax.twinx()
h2 = ax2.scatter(df.index, df['S'],label='S因子',marker='o',color='r')#S值
plt.legend([h1,h2], [h1.get_label(),h2.get_label()], loc='best')
ax.grid()#网格
ax.set_ylabel(u"成交量(万)")
ax.set_title(u"成交量与S因子值")
ax2.set_ylabel(u"S值(10e-4)")
ax.set_xlabel(u"时间序号")
plt.xticks(df.index.values, df['bar_no'])#排序后的图
ax = fig.add_subplot(212)
df = df.sort_values(by='S',ascending=False).reset_index(drop=True)#按S值排序
df['acc_volume_pct'] = df['volume'].cumsum()/df['volume'].sum()#计算累计成交量
df1 = df[df['acc_volume_pct']<=0.2]#累计成交量前20%
df2 = df[df['acc_volume_pct']>0.2]
ax.bar(df1.index,df1['volume'],color='r',width=0.5)#绘制累计成交量前20%的柱状图
h1 = ax.bar(df2.index,df2['volume'],label='成交量',width=0.5)#绘制余下的
ax2 = ax.twinx()
h2 = ax2.plot(df.index, df['acc_volume_pct'],label='累计成交量占比',marker='o',color='g')#累计成交量
plt.legend([h1,h2[0]], [h1.get_label(),h2[0].get_label()], loc='best')
ax.grid()
ax.set_ylabel(u"成交量(万)")
ax.set_title(u"选择聪明钱")
ax2.set_ylabel(u"累计成交量")
ax.set_xlabel(u"时间序号")
plt.xticks(df.index.values, df['bar_no'])

3.3 量化聪明钱对股票后市的情绪

我们划分出了聪明钱的交易后,如何判断聪明钱是对这只股票看多还是看空呢

对于特定股票、特定时段的分钟行情数据,按照上述方法划分出聪明钱的交易之后,我们可以构造聪明钱的情绪因子Q

Q = vwap_smart/vwap_all

vwap_smart和vwap_all分别是聪明钱的成交量加权平均价和该段时间内所有分钟的成交量加权平均价

因子 Q 实际上反映了在该时间段中聪明钱参与交易的相对价位。之所以将其称为聪明钱的情绪因子,是因为因子 Q 的值越大,表明聪明钱的交易越倾向于出现在价格较高处,这是逢高出货的表现,反映了聪明钱的看空,消极情绪;因子Q的值越小,则表明聪明钱的交易多出现在价格较低处,这是逢低吸筹的表现,看多,积极情绪。

我们将情绪因子Q的计算封装成一个函数

def calcQ(data_bar):'''功能:计算Q值参数:DataFrame类型,特定股票一定时间段内的分钟数据(close,volume和S)返回:浮点数,即Q值'''data_bar = data_bar.sort_values(by='S',ascending=False).reset_index(drop=True)#按S值排序data_bar['acc_volume_pct'] = data_bar['volume'].cumsum()/data_bar['volume'].sum()#计算累计成交量smart_bar = data_bar[data_bar['acc_volume_pct']<=0.2]#聪明钱交易,累计成交量前20%#vwmap:volume weighted average price,成交量加权平均价vwap_smart = (smart_bar['close']*smart_bar['volume']).sum()/smart_bar['volume'].sum()vwap_all = (data_bar['close']*data_bar['volume']).sum()/data_bar['volume'].sum()return vwap_smart/vwap_all

3.4因子选股能力验证

本小节对上一小节量化出的聪明钱情绪因子的选股能力进行验证。

样本空间:沪深300成分股,剔除 ST 股和上市未满 60 日的新股,以及涨停、停牌、跌停(原研报为全部A股,但数据量过多,受硬件限制本文缩小了样本范围,做了简化)

测试时间:2013-04-30 到 2016-05-31

测试方法:每个月末时,对于选股空间的所有股票,计算其之前10天的分钟级交易数据的Q值,和该股票次月的收益率。这样每个月可以得到两组序列,分别为每只股票的Q值和次月的收益率,计算其RankIC秩相关系数。可视化测试时间周期内所有月份的两组序列的相关系数,统计显著相关情况。

概念解释

RankIC秩相关系数为两组序列中的元素在序列中的相对位置(即大小顺序)的相关系数。

在因子模型中,因子与收益的相关系数大于0.03即认为是有效的因子。

为了实现对因子的验证,我们封装了两个简单的函数,分别用于

1.获取特定日期满足交易条件的股票(即在选股样本中剔除ST股、涨停、跌停等)

2.获取特定日期所在月的最后一日,用于获取次月的行情数据

def get_stocks(date,index=None):'''功能:根据日期,获取该日满足交易要求的股票相关数据,即剔除ST股、上市未满60天、停牌、跌涨停股参数:date,日期index,指数代码,在特定指数的成分股中选股。缺省时选股空间为全部A股返回:DataFrame类型,索引为股票代码,同时包含了价格数据,方便后续使用'''stocks = get_all_securities(types=['stock'],date=date)#该日正在上市的股票if index:#特定成分股stock_codes = get_index_stocks(index,date=date)#成分股stocks = stocks[stocks.index.isin(stock_codes)]#上市日期大于60个自然日#date = datetime.datetime.strptime(date,'%Y-%m-%d').date()stocks['datedelta'] = date - stocks['start_date']stocks = stocks[stocks['datedelta'] > datetime.timedelta(days=60)]#是否是ST股stocks['is_st'] = get_extras(info='is_st',security_list=list(stocks.index),count=1, end_date=date).T#涨停、跌停、停牌stocks_info = get_price(security = list(stocks.index),fields=['close','high','low','high_limit','low_limit','paused'],count=1,end_date=date,panel=False).set_index('code').drop('time',axis=1)stocks['price'] = stocks_info['close']#顺便保存价格,方便后续运算stocks['paused'] = stocks_info['paused'] == 1#是否停牌stocks['high_stop'] = stocks_info['high'] >= stocks_info['high_limit']#涨停stocks['low_stop'] = stocks_info['low'] <= stocks_info['low_limit']#跌停stocks = stocks[~(stocks['is_st'] | stocks['paused'] | stocks['high_stop'] | stocks['low_stop'])]   return stocks
def last_day_of_month(any_day):#获取某个日期所在月份的最后一天,方便在计算次月收益时获取次月的时间范围next_month = any_day.replace(day=28) + datetime.timedelta(days=4)  # this will never failreturn next_month - datetime.timedelta(days=next_month.day)

万事俱备,我们现在统计每个月份每只股票的Q值和次月收益率,并计算秩相关系数、可视化。

#获取交易日序列
trade_days = get_trade_days(start_date='2013-04-30', end_date='2016-05-31')
#存储结果
result={'months':[],#月份序列'stocks':[],#股票序列'Q':[],#Q值序列'return':[]#次月收益序列
}
days_count = len(trade_days)
for i,date in enumerate(trade_days):#遍历交易日if i == days_count-1:#如果是列表最后一个日期#可交易的股票stocks = get_stocks(trade_days[i],index='000300.XSHG')stocks_list = list(stocks.index)#每只股票下个月的价格next_month_bar = get_bars(stocks_list, count = 1, unit = '1M',fields = ['open','close'],df = True,include_now=True,end_dt = '2016-06-30')'''获取分钟数据,用来计算Q这里一次性获取所有股票的数据,来减少数据请求的次数,加速程序运行'''data = get_minute_data(stocks_list,2400,end_dt=trade_days[i]).reset_index(level=0). rename(columns={'level_0':'code'})data_groups = data.groupby('code')#分钟数据根据股票代码分组result['stocks']+=stocks_listresult['months']+=[trade_days[i].strftime('%Y-%m')]*stocks.shape[0]#依次计算每一只股票的Q值result['Q']+=[calcQ(data_bar) for name,data_bar in data_groups]result['return']+=list((next_month_bar['close']-next_month_bar['open'])/next_month_bar['open'])       break        if trade_days[i+1].month != trade_days[i].month:#每月的最后一个交易日stocks = get_stocks(trade_days[i],index='000300.XSHG')stocks_list = list(stocks.index)next_month_bar = get_bars(stocks_list, count = 1, unit = '1M',fields = ['open','close'],df = True,include_now = True,end_dt = last_day_of_month(trade_days[i+1]))data = get_minute_data(stocks_list,2400,end_dt=date).reset_index(level=0).rename(columns={'level_0':'code'})data_groups = data.groupby('code')result['stocks']+=stocks_listresult['months']+=[date.strftime('%Y-%m')]*stocks.shape[0]result['Q']+=[calcQ(data_bar) for name,data_bar in data_groups]result['return']+=list((next_month_bar['close']-next_month_bar['open'])/next_month_bar['open'])df = pd.DataFrame(result)
'''
因为该段程序需要运行的时间较长,所以将运行出的结果存储到文件中
之后的研究可以直接读取文件
'''
df.to_excel('result.xlsx')
result = pd.read_excel('result.xlsx').drop('stocks',axis=1)
result_group = result.groupby('months')
#存储月份和每月两个序列的秩相关系数
result_df = {'month':[],'RankIC':[]
}
for month,month_result in result_group:result_df['month'].append(month)result_df['RankIC'].append(month_result.corr(method='spearman')['Q']['return'])
#以0.03作为阈值来划分显著和不显著相关
result_df = pd.DataFrame(result_df)
ic_plus = result_df[result_df['RankIC']>0.03]
ic_minus = result_df[result_df['RankIC']<-0.03]
ic_other = result_df[(result_df['RankIC']>=-0.03) &(result_df['RankIC']<=0.03)]
print('显著为负: ',ic_minus.shape[0])
print('显著为正: ',ic_plus.shape[0])
print('不显著:',ic_other.shape[0])#可视化
fig = plt.figure(figsize=(14,5))
ax1 = fig.add_subplot(111)
ax1.bar(ic_other.index, ic_other['RankIC'], align='center', width=0.5, color='pink')
ax1.bar(ic_plus.index, ic_plus['RankIC'], align='center', width=0.5, color='r')
ax1.bar(ic_minus.index, ic_minus['RankIC'], align='center', width=0.5, color='b')
ax1.set_ylabel(u"Rank IC")
ax1.set_title(u"因子 RankIC 的月度序列")
ax1.set_xlabel(u"时间" )
ax1.grid(axis='y')
plt.xticks(result_df.index, result_df['month'],ro

显著为负: 22

显著为正: 7

不显著: 8

由结果来看,股票Q值与次月收益率在大部分时间显著为负,这也许上文在定义Q时的分析一致。Q值越大,聪明钱对该只股票看跌,聪明钱在高位抛售该股,该股次月的收益率下降。

3.5 选股策略的构建与回测

研究方法:每月月底将股票前10日分数数据的Q值排序、根据Q值由小到大等分为5类。每一类分别建仓,可视化每一类的收益情况。

研究结果:在策略运行的时间周期内,5类持仓的收益率具有单调性。即Q值小的组收益率大。这也可以由之前的分析解释,因为Q值小意味着聪明钱在低价吸入,聪明钱具有看多的情绪。

策略构建:基于研究结果,可构建两种策略。

一种是多空对冲策略,即做多第一组的股票。做空第五组的股票,进行对冲。该对冲策略在本文的回测中的收益率高于五组分别做多的收益,且最大回撤更低。在原研报的所有A股的样本中,对冲策略的收益率位于第一组和第三组之间,且最大回撤更低。

另一种是做多第一组的股票,但是要剔除前期涨幅过高的五分之一的样本,原研报将这种选股组合称为SMART组合。

回测规则:每月月底计算Q值、选股、调仓。等权重配置股票,即让每只股票的(价格*持有数)占总资产的比例相同。初始资金100万,交易费率0.003,选股空间、与上文相同。

为了方便回测,我们新建了一个仓位类,来对应每一组的账户。该类具有当前持有的股票列表、对应的价格、每只股票持有数量、现金、账户净值这些属性提供了更新价格、调整仓位的功能,并可以维护现金和账户净值。

class Position():'''为了方便回测,我们新建了一个仓位类,来对应每一组的账户。该类具有当前持有的股票列表、对应的价格、每只股票持有数量、现金、账户净值这些属性提供了更新价格、调整仓位的功能,并可以维护现金和账户净值'''def __init__(self,stocks=np.array([]),price=np.array([]),weight=np.array([]),cash=0):self.stocks = stocksself.price = priceself.weight = weightself.cash = cashif not self.stocks.size:self.net_value = self.cashelse:self.net_value = (self.weight*self.price).sum()+self.cashdef update_price(self,price):#传入一个价格序列,对应持有股票的最新价格for i,p in enumerate(price):if not np.isnan(p):self.price[i] = pself.net_value = (self.weight*self.price).sum()+self.cashdef change_position(self,new_stocks,price,commission):#更新仓位,传入筛选出的股票列表和对应的价格for i,stock in enumerate(self.stocks):#原有股票不在新列表中,需要卖出if stock not in new_stocks:self.cash+=self.price[i]*self.weight[i]*(1-commission)#计算每一只股票应持有的数量new_weight = self.net_value*0.99/len(new_stocks)/pricenew_weight = [int(_) for _ in new_weight]for i,stock in enumerate(self.stocks):#原有股票在新列表中,需要调整数量if stock in new_stocks:weight_chg = new_weight[list(new_stocks).index(stock)] - self.weight[i]self.cash -= self.price[i]*weight_chg\+ abs(self.price[i]*weight_chg)*commissionfor i,stock in enumerate(new_stocks):#新增股票,需要买入if stock not in new_stocks:self.cash -= price[i]*new_weight[i]*(1+commission)self.stocks = new_stockpsself.weight = new_weightself.price = priceself.net_value = (self.weight*self.price).sum()+self.cash

多空对冲策略回测

capital_base = 1000000 #初始资金
commission = 0.003     #交易费率
#五组仓位
position_dict = {1:Position(cash=capital_base),2:Position(cash=capital_base),3:Position(cash=capital_base),4:Position(cash=capital_base),5:Position(cash=capital_base)
}
#净值统计
net_value_dict = {'month':[],#时间1:[],#每一组每个月月末的净值序列2:[],3:[],4:[],5:[]
}
trade_days = get_trade_days(start_date='2013-04-30', end_date='2016-05-31')
days_count = len(trade_days)
for i,date in enumerate(trade_days):#遍历交易日if  i == days_count-1 or trade_days[i+1].month != trade_days[i].month:#print(trade_days[i])#可交易股票stocks = get_stocks(trade_days[i],index='000300.XSHG')stocks_list = list(stocks.index)#股票的前10天的分钟数据,并根据股票分组data = get_minute_data(stocks_list,2400,end_dt=trade_days[i]).reset_index(level=0).rename(columns={'level_0':'code'})data_groups = data.groupby('code')#计算每一只股票的Q值stocks['Q'] = [calcQ(data_bar) for name,data_bar in data_groups]#Q值排序stocks = stocks.sort_values(by='Q').reset_index()lens = stocks.shape[0]#根据Q值的大小等分为5组s_1 = stocks[stocks['Q'].isin(stocks['Q'][:int(0.2*lens)])].reset_index()s_2 = stocks[stocks['Q'].isin(stocks['Q'][int(0.2*lens):int(0.4*lens)])].reset_index()s_3 = stocks[stocks['Q'].isin(stocks['Q'][int(0.4*lens):int(0.6*lens)])].reset_index()s_4 = stocks[stocks['Q'].isin(stocks['Q'][int(0.6*lens):int(0.8*lens)])].reset_index()s_5 = stocks[stocks['Q'].isin(stocks['Q'][int(0.8*lens):])].reset_index()#如果有持仓数据if position_dict[1].stocks.size:#更新持仓价格for cls in range(1,6):position_dict[cls].update_price(price=get_price(                       security = list(position_dict[cls].stocks),count = 1,end_date = trade_days[i],panel = False)['close'])#调仓position_dict[1].change_position(new_stocks=s_1['index'],price = s_1['price'],commission=commission)            position_dict[2].change_position(new_stocks=s_2['index'],price = s_2['price'],commission=commission)position_dict[3].change_position(new_stocks=s_3['index'],price = s_3['price'],commission=commission)position_dict[4].change_position(new_stocks=s_4['index'],price = s_4['price'],commission=commission)position_dict[5].change_position(new_stocks=s_5['index'],price = s_5['price'],commission=commission)#添加该月的结果net_value_dict['month'].append(trade_days[i])for cls in range(1,6):net_value_dict[cls].append(position_dict[cls].net_value)continue#可视化
net_value_df = pd.DataFrame(net_value_dict)
net_value_df.to_excel('net_value_df.xlsx')
net_value_df = pd.DataFrame(net_value_dict)
plt.figure(figsize=(14,6))
net_value_df[1] = (net_value_df[1]/1000000)
net_value_df[2] = (net_value_df[2]/1000000)
net_value_df[3] = (net_value_df[3]/1000000)
net_value_df[4] = (net_value_df[4]/1000000)
net_value_df[5] = (net_value_df[5]/1000000)
net_value_df['1与5对冲'] = net_value_df[1] - net_value_df[5]+1
index=get_bars('000300.XSHG', count = 37, unit = '1M',fields = ['close'],df = True,include_now=True,end_dt = '2016-05-31')['close']
index = index/index[0]
fig = plt.figure(figsize=(14,5))
ax = fig.add_subplot(111)
ax.plot(net_value_df['month'].index,net_value_df[1],label='1组')
ax.plot(net_value_df['month'].index,net_value_df[2],label='2组')
ax.plot(net_value_df['month'].index,net_value_df[3],label='3组')
ax.plot(net_value_df['month'].index,net_value_df[4],label='4组')
ax.plot(net_value_df['month'].index,net_value_df[5],label='5组')
ax.plot(net_value_df['month'].index,net_value_df['1与5对冲'],label='1组与5组对冲',linestyle='--',linewidth=3)
ax.plot(net_value_df['month'].index,index,linestyle='--',label='沪深300',color='black',linewidth=3)
ax.set_xlabel(u"时间")
ax.set_ylabel(u"净值")
ax.set_title(u"分组表现与多空对冲净值")
plt.xticks(net_value_df['month'].index,net_value_df['month'],rotation=90)
plt.legend()

SMART选股策略

capital_base = 1000000
position_dict_2 = {1:Position(cash=capital_base)
}
net_value_dict_2 = {'month':[],1:[]
}trade_days = get_trade_days(start_date='2013-04-30', end_date='2016-05-31')
days_count = len(trade_days)
commission = 0.003
for i in range(days_count):if i == days_count-1 or trade_days[i+1].month != trade_days[i].month:stocks = get_stocks(trade_days[i],index='000300.XSHG')stocks_list = list(stocks.index)data = get_minute_data(stocks_list,2400,end_dt=trade_days[i]).reset_index(level=0).rename(columns={'level_0':'code'})data_groups = data.groupby('code')stocks['Q'] = [calcQ(data_bar) for name,data_bar in data_groups]stocks = stocks.sort_values(by='Q').reset_index()lens = stocks.shape[0]s_1 = stocks[stocks['Q'].isin(stocks['Q'][:int(0.2*lens)])].reset_index(drop=True)month_bar = get_bars(list(s_1['index']), count = 1, unit = '1M',fields = ['open','close'],df = True,include_now=True,end_dt = trade_days[i]).reset_index(drop=True)#剔除涨幅过高的20%的股票s_1['ratio'] = (month_bar['close'] - month_bar['open'])/month_bar['open']s_1 = s_1.sort_values(by='ratio').reset_index(drop=True)lens = s_1.shape[0]s_1 = s_1[s_1['ratio'].isin(s_1['ratio'][:int(0.8*lens)])]if position_dict_2[1].stocks.size:position_dict_2[1].update_price(price=get_price(                       security = list(position_dict_2[1].stocks),count = 1,end_date = trade_days[i],panel = False)['close'])position_dict_2[1].change_position(new_stocks=s_1['index'],price = s_1['price'],commission=commission)            net_value_dict_2['month'].append(trade_days[i])net_value_dict_2[1].append(position_dict_2[1].net_value)#可视化
net_value_df_2 = pd.DataFrame(net_value_dict_2)
net_value_df_2[1] = (net_value_df_2[1]/1000000)
index=get_bars('000300.XSHG', count = 37, unit = '1M',fields = ['close'],df = True,include_now=True,end_dt = '2016-05-31')['close']
index = index/index[0]
fig=plt.figure(figsize=(14,5))
ax = fig.add_subplot(111)
ax.plot(net_value_df_2['month'].index,net_value_df_2[1],label='SMART选股组合')
ax.plot(net_value_df_2['month'].index,index,label='沪深300')
ax.set_xlabel(u"时间")
ax.set_ylabel(u"净值")
ax.set_title(u"SMART选股组合")
plt.xticks(net_value_df_2['month'].index,net_value_df['month'],rotation=90)
plt.legend()

4.总结

本文基本复现了【方正证券-跟踪聪明钱:从分钟行情数据到选股因子】的研究内容,同时得到了与原研报相近的结果。

本文的不足:

1.因为软硬件条件的限制,压缩了原研报的样本空间。

2.缺少原研报中因子风险特性的研究。

5.本文作者

蔡金航 哈尔滨工业大学威海校区 计算机科学与技术学院

舒意茗 哈尔滨工业大学威海校区 汽车工程学院

写在最后

我们是国内普通高校的在校学生,同时也是量化投资的初学者。我们的学校不是清北复交,也没有金融工程实验室,同时地处三线小城,因此我们在校期间较难获得量化实习机会,但我们期待与业界进行沟通、交流。

蔡金航同学是我们其中的一员。其在寻找暑期量化实习时,收到了几家私募和券商金工组的笔试邀请,笔试内容皆为在给定时间内复现出一篇金工研报。蔡同学受到启发,发觉复现金工研报是我们学习量化策略、锻炼程序设计能力同时也是与业界交流的很好的途径。

在蔡同学的建议下,我们开启研报复现系列的创作,记录我们的学习过程,并将我们的创作内容分享出来,与读者们一起交流、学习、进步。

我们的水平有限,创作的内容难免会有错误或不严谨的内容,我们欢迎读者的批评指正。

如果您对我们的内容感兴趣,请联系我们:cai_jinhang@foxmail.com

研报复现系列(一):【方正证券】跟踪聪明钱:从分钟行情数据到选股因子相关推荐

  1. 跟踪聪明钱:从分钟行情数据到选股因子_方正证券

    方正证券_魏建榕_2016-07-08 摘要:利用聪明度指标 S,从分钟数据中筛选出属于"聪明钱"的交易.构造 聪明钱情绪因子Q ,因子Q的值越大,表现聪明钱的交易越倾向于出现在价 ...

  2. 研报复现系列(二):【光大证券】基于阻力支撑相对强度(RSRS)的市场择时

    1.研报概述 本文是券商金工研报复现系列的第二篇,文本复现了[光大证券]的[基于阻力支撑相对强度(RSRS)的市场择时]. 阻力位与支撑位传统的应用方法一般是选取特定的阻力位.支撑位作为阈值来进行突破 ...

  3. 研报复现系列(五)【光大证券】放量恰是入市时:成交量择时初探

    前言 我们是国内普通高校的在校学生,同时也是量化投资的初学者.我们的学校不是清北复交,也没有金融工程实验室,同时地处三线小城,因此我们在校期间较难获得量化实习机会,但我们期待与业界进行沟通.交流. 蔡 ...

  4. 研报复现系列(三):【东莞证券】股吧里说了什么?——基于文本舆情构建股市情绪指标

    1.研报概述 本文是研报复现系列的第三篇,本文复现了[东莞证券]的研报[股吧里说了什么?--基于文本舆情构建股市情绪指标] 该研报试图利用文本情感分析,通过统计情绪词,将股民的评论进行情感分析,联系情 ...

  5. 【每周研报复现】基于阻力支撑相对强度(RSRS)的市场择时

    原创文章第106篇,专注"个人成长与财富自由.世界运作的逻辑, AI量化投资". 今天要复现的研报是:"光大证券_金融工程深度:基于阻力支撑相对强度(RSRS)的市场择时 ...

  6. 精英任务 | 第二期券商研报复现挑战赛

    你是否不知道该如何在量化投资的路上继续向前? 你是否还在苦于没有研究的思路和方向? 你是否还在纠结几千份研报中,到底该去看哪一个? 研报复现第二期来啦,快来参加吧~ 我们从大量的研报中筛选出有意思的研 ...

  7. 精英任务 | 券商研报复现挑战赛

    你是否不知道该如何在量化投资的路上继续向前? 你是否还在苦于没有研究的思路和方向? 你是否还在纠结几千份研报中,到底该去看哪一个? 来参加聚宽的精英任务吧~ 我们从大量的研报中筛选出了有意思的内容,来 ...

  8. 券商研报复现挑战赛|回望来时路,砥砺再出发

    第一期的研报复现大赛已经落下帷幕啦~ 再次感谢朋友们的踊跃参与和大力支持~ 所有的匍匐都只是高高跃起前的热身, 第二期的赛事即将开启,我们期待您的参与! 第一期研报复现结果回顾 第一期研报复现比赛已经 ...

  9. Vitu研报复现挑战,来了解一下

    传统金融里,券商每年都会产生大量有价值的研报,互联网的普及更是让我们每一个人都可以阅读到其内容. 在做投资决策前,我们需要信任这些研究,那么我们必须能够复现它.所以Vitu.AI正在通过可复现性挑战鼓 ...

最新文章

  1. 回溯算法——算法总结(四)
  2. R语言随机森林回归(randomforest)模型构建
  3. python打印类的属性
  4. Centos7.6安装redis
  5. java B2B2C Springcloud多租户电子商城系统-集成项目简介
  6. mysql found row_mysql found_row()使用详解
  7. Java 学习笔记之 线程安全
  8. 中国 IPv6 网民活跃用户达 3.62 亿,但 App 支持与国外差距较大!
  9. 20200707每日一句
  10. 重磅:国刊4区变1区!2021年中科院分区表正式公布!
  11. Mysql数据库的备份与恢复
  12. elasticsearch报错master not discovered yet, this node has not previously joined a bootstrapped (v7+)..
  13. Windows沙拉:开机时自动打开NumLock键背后的故事
  14. 二分图最大匹配的算法
  15. 一名程序员心态的重要性
  16. PHP菜刀在线WEB版源码
  17. 用MyEclipse开发第一个Struts程序
  18. 安晴同学|大榕树下的友谊
  19. 开机黑屏 只显示鼠标 电脑黑屏 只有鼠标 移动 [已成功解决]
  20. DCM影像图片脱敏处理

热门文章

  1. 五年制计算机专业代码,45个五年制的大学专业,除了医学专业,有些专业也要学五年...
  2. Java中的getClass方法
  3. 1000行代码写小游戏(二)
  4. [创业之路-73] :如何判断一个公司或团队是熵减:凝聚力强、上下一心,还是,熵增:一盘散沙、乌合之众?
  5. c语言 读入两个数组,c语言:读入两个学生的情况存入结构数组。
  6. HTML、CSS——制作手机充电特效
  7. 计算机硬盘英语怎么读,硬盘缩写是什么意思
  8. 感动世界的50首歌和他们背后的故事2
  9. php 屏蔽页面鼠标右键,电脑鼠标右键点不出来怎么办
  10. 测试驱动开发在软件开发中的重要性