老读者应该知道,我炒股两年多了。
从最开始的基金,到后来的股票,金额一直不大,最多就加到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。
了解,阻力支撑相对强度,首先要知道什么是阻力位和支撑位。
阻力位是指目标价格上涨时可能遇到的压力,即交易者认为卖方力量开始反超买方,从而价格难以继续上涨或从此回调下跌的价位;
支撑位则是交易者认为买方力量开始反超卖方,从而止跌或反弹上涨的价位。
阻力支撑相对强度是一种阻力位与支撑位的运用方式,它不再把阻力位与支撑位当做一个定值,而是看做一个变量,反应了交易者对目前市场状态顶底的一种预期判断。
我们按照不同市场状态分类来说明支撑阻力相对强度的应用逻辑:
市场在上涨牛市中:
- 如果支撑明显强于阻力,牛市持续,价格加速上涨
- 如果阻力明显强于支撑,牛市可能即将结束,价格见顶
市场在震荡中:
- 如果支撑明显强于阻力,牛市可能即将启动
- 如果阻力明显强于支撑,熊市可能即将启动
市场在下跌熊市中:
- 如果支撑明显强于阻力,熊市可能即将结束,价格见底
- 如果阻力明显强于支撑,熊市持续,价格加速下跌
每日最高价和最低价是一种阻力位与支撑位,它是当日全体市场参与者的交易行为所认可的阻力与支撑。一个很自然的想法是建立最高价和最低价的线性回归,并计算出斜率。即:
当斜率值很大时,支撑强度大于阻力强度。在牛市中阻力渐小,上方上涨空间大;在熊市中支撑渐强,下跌势头欲止。
当斜率值很小时,阻力强度大于支撑强度。在牛市中阻力渐强,上涨势头渐止;在熊市中支撑渐送,下方下跌空间渐大。
RSRS指标的计算,有两种方法,第一种方法是直接将斜率作为指标值,第二种方法是在斜率基础上进行标准化。
以第二种方法为例,RSRS斜率标准分指标择时策略如下:
小试牛刀
OK,买哪支股票,以及何时买,何时卖,这两个问题解决了,我们就可以开始写代码了。
这里需要先掌握,聚宽的使用方法,以及一些api。
这部分比较简单,直接平台的官方手册就行。
编写如下代码:
代码语言:javascript复制'''
策略思路:
选股:财务指标选股
择时: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,我们下期见!