老读者应该知道,我炒股两年多了。
从最开始的基金,到后来的股票,金额一直不大,最多就加到30万。
涨势最好的时候,差不多每天能有个近万的浮盈,偶尔还有过浮盈近两万的时候。
自从今年2月份,股市开启困难模式后,这样的好日子就到头了。
年初,大几万的浮盈,也折损了大半,再加上今年计划要用到大钱,身体被掏空的那种。
股市投资这块就保守了很多,基本固定在10万左右的低仓位,重在参与了。
一直有读者想看我理财类的文章,最开始应允下来,后来仔细想了想。
你说,我一个技术类博主,写理财,那不是不务正业吗?
况且,我也不是学金融出身的,虽然凭运气在股市赚过一些小钱,但毕竟咱不是专业的,不敢乱指挥。
最近突然转念一想,理财+技术,这个路子我倒是可以。
我很喜欢学新知识,不仅仅局限于计算机技术,时刻保持一颗好奇心,什么都想学点。
正好,近期打算出一篇量化交易的视频,探讨探讨人工智能技术,在投资股市这件事上的应用。
学着学着,我发现,这里面的水挺深,量化交易,并没有我想像的那么好做,要学的知识有点多。
上周末,我花费了一天的时间,算是刚刚入个门。
今天,先整理分享下,量化交易的基础知识,为视频做个热身。
量化交易
量化交易就是,借助现代统计学和数学的方法,利用计算机技术来进行交易的证券投资方式。
主要涵盖的知识点如下:
数学、编程、金融、算法都得懂,哪里不会补哪里就行。
量化平台
抓数据,写策略,在线交易,如果自己一个人来做,成本太高,不利于初期的学习。
我调研了一些量化分析平台,可以帮助我们聚焦到学习量化交易的策略学习上。
我觉得可以用来入门的平台有:
聚宽 vnpy
量化交易的平台有很多,比如掘金、米筐、优矿等。
但适合入门的,可以直接看这聚宽和vnpy。
聚宽的社区比较活跃,有不少技术教程,适合新手入门。
https://www.joinquant.com/study
这里的知识点,就有不少可以学习,同时还有很多大佬分享自己的策略。
vnpy推荐的原因在于它是开源的,可以系统学习如何构建一个量化交易系统。
https://github.com/vnpy/vnpy
如果想自己实现一个量化交易的框架,可以从这里参考很多代码。
小试牛刀
聚宽量化交易平台的使用,比较简单。
我们以这个平台为例,讲解一个简单的量化策略。
我们回归问题的本质,买股票无非两点:
买哪支股票 何时买,何时卖
1、买哪支股票
投资者,选股票,最直接的就是看财务报表。
至少是包括资产负债表、损益表、现金流量表,这三表。
这里的数据就太多了,每个表都有各种各样的指标。
这些指标数据,在量化交易里,叫因子。
我理解,就是我们机器学习中,常说的特征,每一个因子都可以算作一个维度的特征。
我们可以,利用这些已知的数据,构建多维的特征数据,然后将它交给机器学习算法,让算法判断这只股票,值不值得购买。
这又回到了,做算法的老生常谈的问题,选择哪些特征,去拟合数据。
妥了,特征工程走起。
这些最底层的特征,属于一种基础的因子。
在量化交易中,还可以根据这些数据,计算出更“高维”的因子,即特征。
比如净资产收益率,英文缩写叫ROE。
净资产收益率就是公司税后利润除以净资产得到的百分比率。
即,净资产收益率=净利润/净资产
净利润,在利润表里,净资产,在资产负债表。
净资产收益率反映股东权益的收益水平,用以衡量公司运用自有资本的效率。
指标值越高,说明投资带来的收益越高。该指标体现了自有资本获得净收益的能力。
净资产收益率,就是通过一些“低维”的特征,计算出的“高维”的特征。
选股票,其实就是根据这些指标,选择出,你认为值得投资的股票。
为了简化策略,这里就简单的,单一的,利用这个净资产收益率ROE,作为我们的价值选股思想的指标。
简单暴力一点,计算当前所有股票的ROE,由大到小排序,选择top10,作为我们的股票持仓。
2、何时买,何时卖
投资者,都想买在低点,卖在高点。
10块钱买,100块卖,赚个差价,赚了90。
这个问题的本质就是:低买高卖。
但现实往往是残酷的。
何时买,何时卖,在量化交易中,有个指标,阻力支撑相对强度,即RSRS。
了解,阻力支撑相对强度,首先要知道什么是阻力位和支撑位。
阻力位是指目标价格上涨时可能遇到的压力,即交易者认为卖方力量开始反超买方,从而价格难以继续上涨或从此回调下跌的价位;
支撑位则是交易者认为买方力量开始反超卖方,从而止跌或反弹上涨的价位。
阻力支撑相对强度是一种阻力位与支撑位的运用方式,它不再把阻力位与支撑位当做一个定值,而是看做一个变量,反应了交易者对目前市场状态顶底的一种预期判断。
我们按照不同市场状态分类来说明支撑阻力相对强度的应用逻辑:
市场在上涨牛市中:
如果支撑明显强于阻力,牛市持续,价格加速上涨 如果阻力明显强于支撑,牛市可能即将结束,价格见顶
市场在震荡中:
如果支撑明显强于阻力,牛市可能即将启动 如果阻力明显强于支撑,熊市可能即将启动
市场在下跌熊市中:
如果支撑明显强于阻力,熊市可能即将结束,价格见底 如果阻力明显强于支撑,熊市持续,价格加速下跌
每日最高价和最低价是一种阻力位与支撑位,它是当日全体市场参与者的交易行为所认可的阻力与支撑。一个很自然的想法是建立最高价和最低价的线性回归,并计算出斜率。即:
$$
\text { high }=\alpha+\beta \cdot \text { low }+\epsilon, \epsilon \sim N\left(0, \sigma^{2}\right)
$$
当斜率值很大时,支撑强度大于阻力强度。在牛市中阻力渐小,上方上涨空间大;在熊市中支撑渐强,下跌势头欲止。
当斜率值很小时,阻力强度大于支撑强度。在牛市中阻力渐强,上涨势头渐止;在熊市中支撑渐松,下方下跌空间渐大。
RSRS指标的计算,有两种方法,第一种方法是直接将斜率作为指标值,第二种方法是在斜率基础上进行标准化。
以第二种方法为例,RSRS斜率标准分指标择时策略如下:
- 取前M日的RSRS斜率时间序列。(M = 600)
- 计算当日RSRS斜率的标准分\(R S R S_{\text {std }}\)
$$
R S R S_{s t d}=\frac{R S R S-\mu_{M}}{\sigma_{M}}
$$
其中,\(\mu_{M}\)为前M日的斜率均值,\(\sigma_{M}\)为前M日的标准差。
3. 若\(R S R S_{\text {std }}\)大于\(S_{b u y}\),则全仓买入;若\(R S R S_{\text {std }}\)小于\(S_{b u y}\),则卖出平仓。
其中,\(\left(S_{\text {buy }}=0.7, S_{\text {sell }}=-0.7\right)\)。
小试牛刀
OK,买哪支股票,以及何时买,何时卖,这两个问题解决了,我们就可以开始写代码了。
这里需要先掌握,聚宽的使用方法,以及一些api。
这部分比较简单,直接平台的官方手册就行。
编写如下代码:
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 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 | ''' 策略思路: 选股:财务指标选股 择时:RSRS择时 持仓:有开仓信号时持有10只股票,不满足时保持空仓 ''' # 导入函数库 import statsmodels.api as sm from pandas.stats.api import ols # 初始化函数,设定基准等等 def initialize(context): # 开启动态复权模式(真实价格) set_option('use_real_price', True) # 过滤掉order系列API产生的比error级别低的log # log.set_level('order', 'error') set_parameter(context) ### 股票相关设定 ### # 股票类每笔交易时的手续费是:买入时佣金万分之三,卖出时佣金万分之三加千分之一印花税, 每笔交易佣金最低扣5块钱 set_order_cost(OrderCost(close_tax=0.001, open_commission=0.0003, close_commission=0.0003, min_commission=5), type='stock') ## 运行函数(reference_security为运行时间的参考标的;传入的标的只做种类区分,因此传入'000300.XSHG'或'510300.XSHG'是一样的) # 开盘前运行 run_daily(before_market_open, time='before_open', reference_security='000300.XSHG') # 开盘时运行 run_daily(market_open, time='open', reference_security='000300.XSHG') # 收盘后运行 #run_daily(after_market_close, time='after_close', reference_security='000300.XSHG') ''' ==============================参数设置部分================================ ''' def set_parameter(context): # 设置RSRS指标中N, M的值 #统计周期 g.N = 18 #统计样本长度 g.M = 1100 #首次运行判断 g.init = True #持仓股票数 g.stock_num = 10 #风险参考基准 g.security = '000300.XSHG' # 设定策略运行基准 set_benchmark(g.security) #记录策略运行天数 g.days = 0 #set_benchmark(g.stock) # 买入阈值 g.buy = 0.7 g.sell = -0.7 #用于记录回归后的beta值,即斜率 g.ans = [] #用于计算被决定系数加权修正后的贝塔值 g.ans_rightdev= [] # 计算2005年1月5日至回测开始日期的RSRS斜率指标 prices = get_price(g.security, '2005-01-05', context.previous_date, '1d', ['high', 'low']) highs = prices.high lows = prices.low g.ans = [] for i in range(len(highs))[g.N:]: data_high = highs.iloc[i-g.N+1:i+1] data_low = lows.iloc[i-g.N+1:i+1] X = sm.add_constant(data_low) model = sm.OLS(data_high,X) results = model.fit() g.ans.append(results.params[1]) #计算r2 g.ans_rightdev.append(results.rsquared) ## 开盘前运行函数 def before_market_open(context): # 输出运行时间 #log.info('函数运行时间(before_market_open):'+str(context.current_dt.time())) g.days += 1 # 给微信发送消息(添加模拟交易,并绑定微信生效) send_message('策略正常,运行第%s天~'%g.days) ## 开盘时运行函数 def market_open(context): security = g.security # 填入各个日期的RSRS斜率值 beta=0 r2=0 if g.init: g.init = False else: #RSRS斜率指标定义 prices = attribute_history(security, g.N, '1d', ['high', 'low']) highs = prices.high lows = prices.low X = sm.add_constant(lows) model = sm.OLS(highs, X) beta = model.fit().params[1] g.ans.append(beta) #计算r2 r2=model.fit().rsquared g.ans_rightdev.append(r2) # 计算标准化的RSRS指标 # 计算均值序列 section = g.ans[-g.M:] # 计算均值序列 mu = np.mean(section) # 计算标准化RSRS指标序列 sigma = np.std(section) zscore = (section[-1]-mu)/sigma #计算右偏RSRS标准分 zscore_rightdev= zscore*beta*r2 # 如果上一时间点的RSRS斜率大于买入阈值, 则全仓买入 if zscore_rightdev > g.buy: # 记录这次买入 log.info("市场风险在合理范围") #满足条件运行交易 trade_func(context) # 如果上一时间点的RSRS斜率小于卖出阈值, 则空仓卖出 elif (zscore_rightdev < g.sell) and (len(context.portfolio.positions.keys()) > 0): # 记录这次卖出 log.info("市场风险过大,保持空仓状态") # 卖出所有股票,使这只股票的最终持有量为0 for s in context.portfolio.positions.keys(): order_target(s, 0) #策略选股买卖部分 def trade_func(context): #获取股票池 df = get_fundamentals(query(valuation.code,valuation.pb_ratio,indicator.roe)) #进行pb,roe大于0筛选 df = df[(df['roe']>0) & (df['pb_ratio']>0)].sort('pb_ratio') #以股票名词作为index df.index = df['code'].values #取roe倒数 df['1/roe'] = 1/df['roe'] #获取综合得分 df['point'] = df[['pb_ratio','1/roe']].rank().T.apply(f_sum) #按得分进行排序,取指定数量的股票 df = df.sort('point')[:g.stock_num] pool = df.index log.info('总共选出%s只股票'%len(pool)) #得到每只股票应该分配的资金 cash = context.portfolio.total_value/len(pool) #获取已经持仓列表 hold_stock = context.portfolio.positions.keys() #卖出不在持仓中的股票 for s in hold_stock: if s not in pool: order_target(s,0) #买入股票 for s in pool: order_target_value(s,cash) #打分工具 def f_sum(x): return sum(x) ## 收盘后运行函数 def after_market_close(context): #得到当天所有成交记录 trades = get_trades() for _trade in trades.values(): log.info('成交记录:'+str(_trade)) #打印账户总资产 log.info('今日账户总资产:%s'%round(context.portfolio.total_value,2)) #log.info('##############################################################') |
左边写好代码,输入回测时间和金额就可以运行了。
我直接回测了2010年1月到2020年1月效果,投资十年的收益:
直接起飞,初始资金50万,赚了几百万,很稳!
我又回测了2020年1月到2021年6月,一年半的收益:
跑输大盘8.35%,不过也没亏,年化率也能有个11.40%,还可以吧。
总结
这个策略,没有用到历史数据,是根据当前的一些指标进行决策的。
投资理财,这方面的知识,还是要学习的,不投资股市,买个银行定期这些也挺好。
我们寒窗苦读,一方面就是想学有所成,赚钱,过个舒服的生活。
学校教我们各种基础知识,唯独很少直接地教我们,如何去赚钱,去理财,管理自己的财富。
所以,自学吧。人生在于折腾,各种知识都学学,挺好,挺有意思。
现在,虽然股市是困难模式,但是仍然有很多机会,我们也可以利用这个时间,补充自己的知识。
年入百万,对于现在的我来说,还是洗洗睡吧,梦里什么都有。
本期硬核,喜欢的朋友,转发,点赞走一波,让我瞧一瞧~
感兴趣的人多,后面继续出。
我是 Jack,我们下期见!
2021年7月10日 上午11:52 沙发
我比较保守,有没有地址或者代码用来测试一起验证呢?
2021年7月10日 下午12:01 板凳
我见过一些打板软件,是记录涨停当天的龙虎榜的机构,通过历史数据分析第二天,这票依然涨停或者盈利的概率。
2021年7月15日 下午4:39 地板
Jack LI飘过,常年服务量化私募大厂技术研发职位,楼主是否可以交换一个联系方式认识一下?不看工作交流交流行业信息也行
2024年2月17日 下午6:30 1层
@Jack LI 你好是否可以交流一下 我也是做过几年的量化 现在想自己做一些测试跑一下市商 这我的q3550590431
2021年10月16日 下午5:54 4楼
pandas.stats.api 这个在 joinQuant上运行不了,编译报错