本文概述
在本教程中,您将进行web抓取,点击金融API并使用htmlwidget制作一个交互式时间序列图表来执行一个简单的算法交易策略。
在本文中, 我将展示如何使用R来收集loyal3上列出的股票, 如何从Yahoo获取历史数据, 然后执行简单的算法交易策略。在此过程中, 你将学习一些Web抓取, 点击财务API的功能和htmlwidget制作交互式时间序列图的功能。
对于此帖子, 交易算法定义为触发购买或出售事件的一组规则, 而不是预测模型或时间序列预测。这是最简单的交易算法, 但是, 如果你有兴趣使用R来更深入地研究金融, 我鼓励你参加srcmini的课程, 以在R中建立定量交易策略。
内容
- 背景
- 设置工作区
- 数据采集
- 检查库存数据
- 简单的交易策略:趋势追踪
- 总结
背景
2015年, 我开始对loyal3进行一些投资。他们的服务与众不同, 是开始你的投资旅程的好地方。 loyal3不向投资者收取交易费用, 而是向公司收取在其平台上上市的费用。前提是喜欢公司服务的人也会购买股票, 并以此成为强大的品牌拥护者。使平台更具吸引力的是, 你可以购买零碎股票。因此, 你可以以10美元的价格买入那只800美元的亚马逊股票, 而当月底每次有一点额外现金时, 就可以再购买10美元的零头。当然, 因为你必须在Windows中进行交易, 并且你的整个投资组合仅限于70支股票, 所以存在摩擦成本, 但是loyal3代表了探索股权培训的一种有趣且低成本的方式。只需10美元, 你就可以在游戏中放置真实的皮肤!
需要明确的是, 我拥有典型的退休和投资帐户, 但我喜欢loyal3在该应用程序上的简洁界面, 并且无需付费。我最终会比共同基金更频繁地检查自己的忠诚投资组合, 原因仅在于查看我直接挑选的股票的表现既容易又有趣。
可在www.loyal3.com上获得的股票
设置工作区
首先, 将库加载到你的环境中。这些天, 我几乎总是使用rvest进行网页抓取。还有其他可以工作的软件包, 包括RSelenium, 但我喜欢rvest可以轻松执行。
第二个程序包pbapply是可选的, 因为它只是将进度条添加到了apply函数。由于你可能会抓取数百个网页, 因此进度条可能有助于估计时间。
接下来, TTR是我刚刚开始研究的软件包。该库用于构建”技术交易规则”。尽管你将在本文中学习简单的交易算法, 但TTR软件包可以执行更复杂的计算, 值得学习。
dygraphs库是快速开放源代码JavaScript图表库的包装。它是使R制图更加动态的htmlwidget之一, 并且是html文件的一部分, 而不是静态图像。最后, 使用lubridate软件包可轻松进行日期操作。
library(rvest)
library(pbapply)
library(TTR)
library(dygraphs)
library(lubridate)
数据采集
所有的loyal3股票都列在单个页面上。在查找单个每日股票价格以建立交易算法之前, 你需要收集所有可用的股票行情自动收录器。首先要做的是将stock.list声明为URL字符串。接下来使用read_html(), 以便你的R会话将创建Internet会话并将页面上的所有html信息收集为XML节点集。页面CSS具有一个名为” .company-name”的ID。调用html_nodes()以仅选择与此节点关联的XML数据时, 将此参数用作参数。最后, 使用html_text(), 以便收集公司名称的实际文本值。
stock.list<-'https://www.loyal3.com/stocks'
stocks<-read_html(stock.list)
stocks.names<-html_nodes(stocks, '.company-name')
stocks.names<-html_text(stocks.names)
要检查loyal3上可用的库存, 可以将stocks.names对象打印到控制台。这将公司名称作为文本向量返回。
stocks.names
为了研究股票价格, 你需要先获得股票代码。在loyal3网站上时, 你可以单击公司图块以加载带有股票代码和其他公司信息的页面。
在股票上使用html_nodes(), 可以拉出所有标有” a”的节点。在HTML中, <a>标记定义了一个超链接, 用于将一个页面链接到另一页面。在超链接标记中, ” href”是指确切的URL地址。因此, 如果你传递” href”, 则html_attr()将提取页面上所有链接的URL。
经过手动检查后, 我发现页面上的第54到123链接代表我需要的公司页面, 以便刮擦行情自动收录器的信息。最后一行使用paste0()将基本URL字符串‘http:// www.loyal3.com`连接到特定的公司页面, 例如” / WALMART”。例如, http://www.loyal3.com/WALMART:
loyal.links<-html_nodes(stocks, "a")
loyal.links<-html_attr(loyal.links, "href")
stock.links<-paste0('http://www.loyal3.com', loyal.links[54:123])
公司的每个页面上都有说明, 最近的收盘价和股票代码。所有公司页面的组织方式都相同, 因此可以使用自定义函数get.ticker()提取股票代码。
在公司的网页中, 有一个名为”报价价格”的表格。该函数将导航到公司页面, 标识适当的表, 并使用html_text()提取文本。最后, 将sub()与正则表达式^([[[:alpha:]] *)。*和\\ 1一起使用将保留所有字母字符。结果是删除了任何特殊字符(如$)和任何数字字符(如收盘价)。当该功能读取70页中的每一页时, 它只会收集股票报价器。
get.ticker<-function(url){
x<-read_html(url)
x<-html_node(x, '.ticker-price')
x<-html_text(x)
x<-sub("^([[:alpha:]]*).*", "\\1", x)
return(x)
}
阿里巴巴的loyal3股票页面, 在该页面中, 包含股票行情代码BABA的表格位于粗体下方
有了自定义函数, 可以使用pblapply()将其应用于包含每个公司页面的每个stock.links。生成的对象stock.tickers是单个股票行情清单, 每个元素对应于一个单独公司。
stock.tickers<-pblapply(stock.links, get.ticker)
将元素列表更改为平面对象的一种方法是使用do.call()。在这里, 你将应用rbind将每个列表元素行绑定到单个向量中。最后, 使用符号和公司名称信息创建一个数据框。
stock.ticks<-do.call(rbind, stock.tickers)
stock.ticks<-data.frame(symbol=stock.ticks, name=stocks.names)
为了使你的分析保持一致, 你可能希望限制收集到的每种股票的历史信息量。 Sys.Data()函数将日期对象存储为年, 月和日。使用年份和整数是从start.date对象中减去特定时间量的一种方法。
start.date<-Sys.Date()
end.date<-Sys.Date()-years(3)
要获取Yahoo财务数据, 必须将日期对象更改为不带破折号的简单字符对象。在start.date和end.date上使用全局替换函数gsub()将更改类并同时删除破折号。在gsub()中, 传入字符模式进行搜索, 然后输入替换字符。在这种情况下, 替换模式是两个引号之间的空字符。最后一个参数是gsub()将应用于的对象。
start.date<-gsub('-', '', start.date)
end.date<-gsub('-', '', end.date)
TTR()函数getYahooData()接受一个股票代码以及开始和结束日期。该函数返回具有时间序列信息的数据帧。每行是一个日期, 列中包含诸如股票的”开盘价”, “高价”, “低价”和”收盘价”之类的信息。由于你要查找多个公司, 因此可以使用lapply()或pblapply()。传入公司符号矢量, 然后传入函数getYahooData(), 然后传入日期信息。每次将getYahooData()应用于股票代码时, 日期对象都是可循环使用的参数。
stocks.ts<-pblapply(stock.ticks$symbol, getYahooData, end.date, start.date)
为了使选择返回的列表stocks.ts更加容易浏览, 可以将名称添加到列表元素。将名称与stocks.ts对象一起使用时, 会将名称声明为原始的$ symbol向量。
names(stocks.ts)<-stock.ticks$symbol
在处理大型列表时, 我喜欢检查结果对象以确保结果是我期望的结果。现在元素已经有了名称, 你可以直接引用它们。在此示例中, 你正在检查AMC Entertainment Holdings(AMC)的前6行。在引用$ AMC时在列表上使用head()将返回此股票的时间序列的一部分:
head(stocks.ts$AMC)
检查库存数据
当我收听财经新闻时, 评论员经常参考图表。尽管其他人进行高频交易和积极管理, 许多小投资者仍然参考图表以获取洞察力。可以使用绘图快速显示时间序列对象。传入引用命名元素(例如$ AMC)的列表, 然后传入要显示的列, 此处为$ Close。
plot(stocks.ts$AMZN$Close)
前面的图是静态的, 不是很有趣。
让我们使用JavaScript库制作可以浏览的图表。在此代码段中, 你可能会观察到”%>%”或管道运算符。管道运算符是编写简洁代码的好方法。它将对象转发到下一个函数, 而不会像你在本文前面那样强制你重写对象名称。
在此示例中, 你将创建一个指向Twitter股票的记号, $ TWTR, 然后是你要绘制的列, $ Close。在dygraph中, main添加在引号之间指定的标题。使用”%>%”, 将整个对象转发到下一个函数dyRangeSelector()。你可以使用带有起始日期和结束日期字符串的c()来指定默认日期范围。产生的HTML对象是Twitter股票的动态时间序列, 底部带有日期滑块。
请记住, 要更改显示的权益, 请更改stocks.ts列表中的股票代码, 然后更改图形标题。
dygraph(stocks.ts$TWTR$Close, main = "TWTR Stock Price") %>%
dyRangeSelector(dateWindow = c("2013-12-18", "2016-12-30"))
这是Twitter股票的基本字形
简单的交易策略:趋势追踪
高频交易者和对冲基金使用复杂的模型和基于规则的方法来执行交易。如果你想了解更多信息, 建议你访问www.quantopian.com以获取高级方法。有关更简单的方法, 请从以下页面开始:www.Investopedia.com。
在下面的代码中, 你将可视化一个简单的动量交易策略。基本上, 你将要计算股票价格的200天和50天移动平均线。在任何一天中, 如果50天移动平均线高于200天移动平均线, 你将购买或持有头寸。在200天平均数大于50天移动平均数的日子里, 你将卖出股票。该策略称为趋势跟随策略。两个基于时间的平均值之间的正负性质代表着股票的动量。
TTR软件包提供SMA()来计算简单的移动平均线。在此代码段中, 你正在检查Twitter的200天和50天移动平均线的前6个值。 SMA()通过传入股票和特定列(如收盘价)的时间序列数据来工作。这是TWTR股票收盘价的单一向量。第二个参数是一个整数, 表示移动平均值的观测次数。如果不使用head(), SMA()函数将返回所有值。
head(SMA(stocks.ts$TWTR$Close, 200))
head(SMA(stocks.ts$TWTR$Close, 50))
既然你已经详细研究了移动平均线功能, 就需要将其应用于70只股票中的每只。 stocks.ts是包含单个股票数据的70个数据框的列表。每个数据框的第四列包含我们要用于移动平均线的收盘价。
定制函数mov.avgs()接受单个股票数据框以计算移动平均值。第一行选择收盘价, 因为它索引[, 4]来创建stock.close。接下来, 该函数使用ifelse检查数据帧中的行数。具体来说, 如果数据帧中的行数小于(2 * 260), 则该函数将创建一个移动平均值为” NA”的数据帧。
我选择此数字是因为一年大约有250个交易日, 因此这将检查时间序列的长度是否约为2年或更长。 Loyal3有时可以使用IPO, 并且如果股票是新上市的, 则没有足够的数据来获取200天移动平均线。但是, 如果nrow值大于2 * 260, 则该函数将使用原始数据以及200和50天移动平均值作为新列创建一个数据框。使用colnames, 我声明列名称。函数的最后一部分使用complete.cases检查200天移动平均列中的值。没有值的任何行都将删除到最终结果中。
mov.avgs<-function(stock.df){
stock.close<-stock.df[, 4]
ifelse((nrow(stock.df)<(2*260)), x<-data.frame(stock.df, 'NA', 'NA'), x<-data.frame(stock.df, SMA(stock.close, 200), SMA(stock.close, 50)))
colnames(x)<-c(names(stock.df), 'sma_200', 'sma_50')
x<-x[complete.cases(x$sma_200), ]
return(x)
}
有了此mov.avgs()函数, 你可以使用pblapply()将移动平均值计算添加到70个数据帧的每一个中。
stocks.ts<-pblapply(stocks.ts, mov.avgs)
使用下面的代码以图表显示股票的移动平均线。再次, 此代码使用”%>%”运算符转发对象。 dygraph()函数接受stocks.ts $ FOX数据框。具体来说, 该数据帧由列名称以c(‘sma_200’, ‘sma_50’)索引。此对象在接下来的2行中传递给dySeries()。你可以按名称引用一列, 因此dySeries()分别在第2行和第3行中为” sma_50″和” sma_200″值绘制了一条线。该对象再次转发到dyRangeSelector()以调整选择器的高度。最后, 我添加了一些阴影来定义你想购买或持有股票的期限, 以及应该出售股票或根据头寸保留价格的时期。
dygraph(stocks.ts$FOX[, c('sma_200', 'sma_50')], main = 'FOX Moving Averages') %>%
dySeries('sma_50', label = 'sma 50') %>%
dySeries('sma_200', label = 'sma 200') %>%
dyRangeSelector(height = 30) %>%
dyShading(from = '2016-4-28', to = '2016-7-27', color = '#CCEBD6') %>%
dyShading(from = '2016-7-28', to = '2016-12-30', color = '#FFE6E6')
这是交互式时间序列的最终结果。
带有阴影区域的FOX移动平均线, 用于购买/持有与出售
总结
作为一个崭新的算法交易者, 你不需要绘制所有70股股票。相反, 你将希望每天运行代码并添加一种编程方式来识别符合基于规则的方法的股票, “如果50天移动平均线高于200天移动平均线, 则进行购买”。当你查看前面的图表时, 绿色部分是你购买FOX股权的时间。红色部分代表出售你的股票而不是重新进入的时间。
由于图形是交互式的, 因此可以使用滑块来调整视觉尺寸。基于这种简单的算法交易方法, 现在可能是购买FOX的好时机! 2016年12月30日是一个交易日, 其中50天移动平均线比200天移动平均线高出0.01美元!
FOX股权的放大部分
当然, 请记住所有投资都会损失价值。要了解有关金融和算法交易的更多信息, 请在此处查看srcmini的课程。
评论前必须登录!
注册