视频

了解更多
总的来说,世界上有两种类型的投资者。基本面投资者在决定是否投资一家公司时,会关注公司的基本面指标,例如其商业模式、收入、利润、现金流、当前估值、风险和增长前景。沃伦·巴菲特通过其基本面研究发现被低估的公司而闻名,并成为世界上最富有的人之一。
另一方面,技术分析投资者很少或根本不关注公司的基本面,而是将注意力集中在从数百个技术指标中推导出买入、卖出和持有信号。这些技术分析投资者进行日内、周度或月度交易。
我在此并非要争论这两种投资风格孰优孰劣。但无论是基本面投资者还是技术分析投资者,都是基于数百乃至数千个数据源进行研究、分析和决策。
基本面投资者研究全球数千家公司和数百个行业的资产负债表、损益表、现金流量表、人口趋势、主题趋势和社会趋势。他们在此数据基础上构建金融模型或分析,以更好地理解公司的发展轨迹和增长前景。
技术分析投资者每小时或每天查看数百个技术指标来获取投资信号。依赖技术指标的投资者必须处理跨越多个时间框架的庞大数据集来构建他们的交易策略。他们可能需要查询大量的指标,并且要求几乎即时的答案。他们可能需要快速调整其算法和交易策略以适应快速变化的市场。Redis Enterprise 可以应对所有这些挑战。
最近,我撰写了一篇关于为什么Redis Enterprise 是金融行业不可或缺的工具的文章。在这篇博文中,我将展示如何使用 RedisTimeSeries 来存储、聚合和查询股票价格和技术指标。我将概述的这些原则也可以用于存储和查询公司的财务信息或基本面投资者使用的任何其他时间序列数据。
RedisTimeSeries 模块可以摄取和查询数百万个事件、样本和定价数据。RedisTimeSeries 最适合存储相关的时间和值对,以帮助在从物联网到医疗保健再到金融等用例中发现趋势。RedisTimeSeries 提供了平均值、总和、最小值、最大值、标准差、范围等聚合功能,可帮助您轻松分析数据并做出决策。
在这篇文章中,我将演示一个模型,说明如何使用 RedisTimeSeries 存储股票价格和技术指标。我将介绍如何为价格和指标创建各种时间序列,展示如何在原始时间序列之上创建聚合,并演示使用各种 RedisTimeSeries 命令批量摄取和查询时间序列数据的便捷性。我还提供了 Python 示例代码,您可以将其用作自己用例的起点。
无论对错,许多人认为道琼斯工业平均指数 (DJIA) 是美国经济的晴雨表。我想跟踪道琼斯指数中所有 30 只股票的技术指标以及这些股票的价格和交易量。我首先跟踪道指成分股高盛的股票价格和该股票的一项技术指标。我最喜欢的一项技术指标是相对强弱指数 (RSI)。RSI 是一种动量指标,用于衡量股票是否处于超买或超卖区域。当 RSI 接近或低于 30 时,该股票可能被视为超卖,并可能提供买入机会。同样,当 RSI 升至 70 以上时,可能进入超买区域,预示着卖出的好时机。
高盛集团的相对强弱指数
在交易时间,RSI 与任何其他技术指标一样,会随着高盛股票供需执行交易而变化。我们可以使用 RedisTimeSeries 模块来帮助回答许多关键问题:
我们可以使用 RedisTimeSeries 查询以编程方式识别指定时间段内的最小和最大 RSI 值以及股票价格。例如,如果我想找出交易日每 15 分钟内的最小和最大 RSI 数值呢?当 RSI 达到或接近 30 时,我可能想生成警报、下达交易指令,或者启动另一个复杂的交易流程来分析其他技术指标,然后再决定买入或卖出。您想做的任何事情都可以轻松地在 RedisTimeSeries 数据库中建模。
上手体验 RedisTimeSeries 最简单的方法是运行 RedisTimeSeries 的 Docker 镜像。
执行以下命令拉取并运行 Docker 镜像
docker run -p 6379:6379 -it --rm redis/redistimeseries
Redis 团队有意做出了一项设计决策,让 RedisTimeSeries 模块在每个时间序列中只存储一个指标。这种数据模型的简洁性使得数据的插入和检索速度极快。您可以根据需要添加新的时间序列,而无需担心破坏现有应用程序。这意味着您可以轻松添加新的数据源,而无需担心破坏数据库模式或您的应用程序。
RedisTimeSeries 容器启动并运行后,您可以使用 Python 连接到服务器(请确保 IP 地址或主机名正确),如下所示
from redistimeseries.client import Client rts = Client(host='127.0.0.1', port=6379)
遵循在每个时间序列中存储单个指标的设计原则,我们可以为道指的每只股票在各自的时间序列中存储盘中交易价格和 RSI。下面,我为高盛集团 (Goldman Sachs Group, Inc. NYSE: GS) 创建了一个时间序列。 我将高盛的盘中 RSI 命名为 ‘DAILYRSI:GS’,并为每个时间序列应用了各种标签——为时间序列打标签可以让您使用标签查询所有键。
rts.create('DAILYRSI:GS', labels={ 'SYMBOL': 'GS' , 'DESC':'RELATIVE_STRENGTH_INDEX' , 'INDEX' :'DJIA' , 'TIMEFRAME': '1_DAY' , 'INDICATOR':'RSI' , 'COMPANYNAME': 'GOLDMAN_SACHS_GROUP'})
在这里,我创建了一个名为 ‘INTRADAYPRICES:GS’ 的时间序列,用于存储高盛的盘中股票价格
rts.create('INTRADAYPRICES:GS', labels={ 'SYMBOL': 'GS' , 'DESC':'SHARE_PRICE' , 'INDEX' :'DJIA' , 'PRICETYPE':'INTRADAY' , 'COMPANYNAME': 'GOLDMAN_SACHS_GROUP'})
接下来,我对特定 15 分钟时间框架内的 RSI 数据创建了各种聚合。(我们可以创建更长或更短时间框架的聚合来满足我们的交易需求。)这些聚合使我们能够查看 RSI 的第一个、最后一个、最小值、最大值和范围值。要创建聚合,我们首先创建一个时间序列来存储聚合结果,然后创建一个规则,用聚合值填充该时间序列。在本例中,我们创建了一个名为 ‘DAILYRSI15MINRNG:GS’ 的时间序列来存储 15 分钟时间段内的 RSI 范围。 ‘createrule’ 在每个 15 分钟时间框架内对原始数据 (‘DAILYRSI:GS’) 应用范围函数,并将其聚合到 ‘DAILYRSI15MINRNG:GS’ 中。
rts.create('DAILYRSI15MINRNG:GS', labels={ 'SYMBOL': 'GS' , 'DESC':'RELATIVE_STRENGTH_INDEX' , 'INDEX' :'DJIA' , 'TIMEFRAME': '15_MINUTES' , 'AGGREGATION': 'RANGE' , 'INDICATOR':'RSI' , 'COMPANYNAME': 'GOLDMAN_SACHS_GROUP'}) rts.createrule('DAILYRSI:GS', 'DAILYRSI15MINRNG:GS', 'range', 900)
在这里,我创建了几个规则来计算交易日每 15 分钟间隔内高盛股票价格的范围和标准差
rts.create('INTRADAYPRICES15MINRNG:GS' , labels={ 'SYMBOL': 'GS' , 'DESC':'SHARE_PRICE' , 'INDEX' :'DJIA' , 'PRICETYPE':'RANGE' , 'AGGREGATION': 'RANGE' , 'DURATION':'15_MINUTES' , 'COMPANYNAME': 'GOLDMAN_SACHS_GROUP'}) rts.createrule('INTRADAYPRICES:GS’ ,'INTRADAYPRICES15MINRNG:GS' ,'range', 900) rts.create('INTRADAYPRICES15MINSTDP:GS' , labels={ 'SYMBOL': 'GS' , 'DESC':'SHARE_PRICE' , 'INDEX' :'DJIA' , 'PRICETYPE':'STDDEV' , 'AGGREGATION': 'STDDEV' , 'DURATION':'15_MINUTES' , 'COMPANYNAME': 'GOLDMAN_SACHS_GROUP'}) rts.createrule( 'INTRADAYPRICES:GS' , 'INTRADAYPRICES15MINSTDP:GS' , 'std.p', 900)
您可以以类似的方式为道琼斯工业平均指数 (DJIA) 中的所有 30 只股票创建时间序列。
有两种方法可以将数据摄取到 RedisTimeSeries 中。TS.ADD 命令允许您将每个股票价格或技术指标添加到时间序列。但由于金融市场数据几乎是连续产生的,您需要向 RedisTimeSeries 添加多个样本,因此最好使用 TS.MADD 方法。MADD 函数接受一个元组列表作为参数。每个元组包含时间序列键的名称、时间戳和值
您可以使用以下 Python 命令将数据插入到时间序列键中
rts.madd(<RSIIndicatorList>)
与 RedisTimeSeries 中的大多数操作一样,查询数据库也很简单。股票价格或技术指标的范围和标准差是波动性的指标。以下查询可以帮助您查看高盛股票价格在每个 15 分钟间隔内的价格范围和标准差
rts.range( 'INTRADAYPRICES15MINRNG:GS' , from_time = 1603704600 , to_time = 1603713600)
这个范围聚合查询会给出以下结果集
[(1603704600, 1.75999999999999), (1603705500, 0.775000000000006), (1603706400, 0.730000000000018), (1603707300, 0.449999999999989), (1603708200, 0.370000000000005), (1603709100, 1.01000000000002), (1603710000, 0.490000000000009), (1603710900, 0.89500000000001), (1603711800, 0.629999999999995), (1603712700, 0.490000000000009), (1603713600, 0.27000000000001)]
正如这个查询结果所示,在 2020 年 10 月 26 日美国东部时间上午 9:30 交易日开始时(整数时间戳 = 1603704600),高盛股票波动较大,交易范围为 1.75 美元。现在将其与接下来的 15 分钟(从 10 月 26 日上午 9:45 开始,整数时间戳 = 1603705500)进行比较,波动性下降,范围为 0.77 美元。高盛股票的价格范围在随后的 15 分钟间隔内持续下降,波动性从未回到开盘 15 分钟内达到的水平。
来自 RedisTimeSeries 的这些数据可以轻松地在仪表盘和图表中可视化。下面的图表显示了高盛股票在 15 分钟间隔内的价格范围
下面的图表以折线图格式显示了相同的数据,表明随着时间推移,高盛的交易价格范围变得更加紧密(此图表在 x 轴上显示整数时间戳)
您可以使用另一种波动性度量指标——标准差——作为聚合函数进行类似的查询
rts.range( 'INTRADAYPRICES15MINSTDP:GS' , from_time = 1603704600 , to_time = 1603713600)
[(1603704600, 0.54657783830434), (1603705500, 0.23201149395202), (1603706400, 0.196072381345986), (1603707300, 0.160267138157647), (1603708200, 0.116990621700049), (1603709100, 0.28043101744222), (1603710000, 0.144379900126934), (1603710900, 0.327611558618967), (1603711800, 0.163118915546951), (1603712700, 0.151417199675549), (1603713600, 0.0963889432843203)]
这开启了许多有趣的可能。假设您想知道当盘中 RSI 值介于 30 到 40 之间时高盛股票的价格。您可以查询 RSI 时间序列和股票价格时间序列,以确定有利可图的交易入场点。
在这里,我正在查询高盛在 1605260100(美国东部时间 2020 年 11 月 13 日上午 9:35)和 1605260940(当天美国东部时间上午 9:49)之间时间范围内的 RSI 值。
dailyGSRSIValue = rts.range( 'DAILYRSI:GS' , from_time = 1605260100 , to_time = 1605260940)
查询发现,在 1605260820(美国东部时间上午 9:47)时,RSI 值为 34.2996427544861。
[(1605260100, 75.0305441024708), (1605260160, 81.6673948350152), (1605260220, 83.8852225932517), (1605260280, 85.9469082344746), (1605260340, 94.3803586011592), (1605260400, 92.2412262502652), (1605260460, 85.6867329371465), (1605260520, 87.9557361513823), (1605260580, 89.9407873066781), (1605260640, 57.1512452602676), (1605260700, 50.5638232111769), (1605260760, 35.2804436894564), (1605260820, 34.2996427544861), (1605260880, 54.5486275202972), (1605260940, 64.7593307385219)]
现在,我可以查询与 RSI 查询所用时间间隔相同的高盛盘中价格,或者通过编程方式更改查询,以反映 RSI 值在 34.29 时的价格。这里有一个使用与 RSI 查询相同时间框架的示例。
dailyGSPrice = rts.range( 'INTRADAYPRICES:GS' , from_time = 1605260100 , to_time = 1605260940)
查询返回了指定范围内的高盛股票价格:在 1605260820(美国东部时间 2020 年 11 月 13 日上午 9:47),价格为 217.18 美元。
[(1605260100, 216.57), (1605260160, 216.73), (1605260220, 217.08), (1605260280, 217.17), (1605260340, 217.87), (1605260400, 218.05), (1605260460, 217.91), (1605260520, 218.0), (1605260580, 218.11), (1605260640, 218.02), (1605260700, 217.72), (1605260760, 217.22), (1605260820, 217.18), (1605260880, 217.46), (1605260940, 217.61)]
RedisTimeSeries 提供了一种强大的方式,可以一次性查询多个时间序列。TS.MGET 命令允许您使用过滤器跨多个时间序列进行查询。我们已经创建了各种时间序列并为其附加了标签。现在这些标签可以作为过滤器来跨时间序列进行查询。
以下 Python 代码应用了基于两个标签的两个过滤器:“DESC”和“TIMEFRAME”。参数 “with_labels=False” 允许返回的结果集不包含每个值的标签
allRSIValues = rts.mget(filters=['DESC=RELATIVE_STRENGTH_INDEX','TIMEFRAME=1_DAY'], with_labels=False)
此查询将呈现类似此处所示的结果,返回多只股票的最新 RSI 值
[{'DAILYRSI:BA': [{}, 1605261060, 62.2048922111768]}, {'DAILYRSI:CAT': [{}, 1605261060, 68.3834400302296]}, {'DAILYRSI:CRM': [{}, 1605261060, 59.2107333830133]}, {'DAILYRSI:CSCO': [{}, 1605261060, 52.7011052724688]}, {'DAILYRSI:CVX': [{}, 1605261060, 62.9890368832232]}, {'DAILYRSI:DOW': [{}, 1605261060, 73.597680480764]}, {'DAILYRSI:GS': [{}, 1605283140, 41.182852552541]}, {'DAILYRSI:IBM': [{}, 1605261060, 65.3742140862697]}, {'DAILYRSI:JPM': [{}, 1605261060, 77.7760292843745]}, {'DAILYRSI:KO': [{}, 1605261060, 26.8638381005608]}, {'DAILYRSI:MMM': [{}, 1605261060, 65.7852833683174]}, {'DAILYRSI:MRK': [{}, 1605261060, 38.9991886598036]}, {'DAILYRSI:UNH': [{}, 1605261060, 74.2672428885775]}, {'DAILYRSI:VZ': [{}, 1605261060, 33.177554436462]}, {'DAILYRSI:WBA': [{}, 1605261060, 47.3877762365391]}]
如果我将 “with_labels=True” 设置为 True,则结果将包含每个时间序列上的所有标签,如下所示
[{'DAILYRSI:BA': [{'SYMBOL': 'BA', 'DESC': 'RELATIVE_STRENGTH_INDEX', 'INDEX': 'DJIA', 'TIMEFRAME': '1_DAY', 'INDICATOR': 'RSI', 'COMPANYNAME': 'BOEING'}, 1605261060, 62.2048922111768]}, {'DAILYRSI:CAT': [{'SYMBOL': 'CAT', 'DESC': 'RELATIVE_STRENGTH_INDEX', 'INDEX': 'DJIA', 'TIMEFRAME': '1_DAY', 'INDICATOR': 'RSI', 'COMPANYNAME': 'CATERPILLAR'}, 1605261060, 68.3834400302296]}, {'DAILYRSI:CRM': [{'SYMBOL': 'CRM', 'DESC': 'RELATIVE_STRENGTH_INDEX', 'INDEX': 'DJIA', 'TIMEFRAME': '1_DAY', 'INDICATOR': 'RSI', 'COMPANYNAME': 'SALESFORCE'}, 1605261060, 59.2107333830133]}]
这篇博文展示了 RedisTimeSeries 的众多命令中的一部分,说明如何灵活地构建依赖于时间序列数据的金融应用。例如,股票交易员需要能够根据数十个变量实时做出高风险决策。RedisTimeSeries 是无模式的,这意味着您无需定义模式即可加载数据,可以即时添加新字段,或者在业务情况变化时更改您的数据模型。其实时性能和简单的开发者体验使得处理时间序列数据充满乐趣!
您可以在 GitHub 上找到这篇博文的示例代码。 您可以在这里了解更多关于 RedisTimeSeries 的信息。