@TOC[1] Here's the table of contents:
本文作者为Neo4j社区技术专家Tomaz Bratanic,帮助我们了解如何使用股票价格之间的相关性来推断股票之间的相似性网络,然后使用该网络信息来帮助我们分散投资组合。
Diversify Your Stock Portfolio with Graph Analytics[2],以下内容为本博客翻译整理。
几周前,我偶然发现了布莱恩特·艾维写的一篇文章【模式驱动的洞察:用Neo4j和Power BI可视化股票交易量相似性[3]】。
这让我对如何使用图数据来分析股票市场产生了兴趣。经过一番研究,我发现了这篇【金融市场风险的分散:最好投资外围市场[4]】研究论文。作者通过检查股票之间的相关性来推断股票之间的社区网络,然后在网络中搜索外围股票以帮助分散股票投资组合。作为研究论文的结论,作者认为这种技术可以通过分散您的投资来降低风险,并且有趣的是可以增加你的收益。
免责声明:这不是投资建议,您应该在投资前进行自己的研究。
图片来源:Daniel Lloyd Blunk-Fernández on Unsplash
我们将使用Kaggle的NASDAQ-100股票价格数据集[5]的一个子集。该数据集包含过去十年102支股票的价格和交易量信息。
对于这篇文章,我准备了一个子集 CSV 文件,其中包含 2021年5月至2021年9月之间的股票价格和交易量信息。
我们将使用以下图模型来存储股票信息:
图数据模型
每支股票将被表示为一个单独的节点。我们将每个股票的价格和交易量信息存储为股票交易日节点的链接列表。
Stock
节点使用股票名称唯一进行合并,StockTradingDay
节点由交易日、收盘价、交易量表示唯一合并。使用链表模式是我在 Neo4j 中对时间序列数据进行建模时使用的通用图模型。
如果你想复现这篇博文中的例子,我建议您在Neo4j Sandbox[6]中打开一个空白项目进行。
Neo4j Sandbox提供了 Neo4j 数据库的免费云实例,这些实例预装了 APOC 和 Graph Data Science 插件。您可以在 Neo4j 浏览器中复制以下 Cypher 语句以导入股票和交易信息。
:auto USING PERIODIC COMMIT
LOAD CSV WITH HEADERS FROM "https://raw.githubusercontent.com/tomasonjo/blog-datasets/main/stocks/stock_prices.csv" as row
MERGE (s:Stock{name:row.Name})
CREATE (s)-[:TRADING_DAY]->(:StockTradingDay{date: date(row.Date), close:toFloat(row.Close), volume: toFloat(row.Volume)});
加载csv数据
接下来,我们需要在股票交易日节点之间创建一个链表。使用
apoc.nodes.link
我们可以很容易地用这个过程创建一个链表。我们还将股票收盘价按交易日排序后存储为股票节点的列表属性。
MATCH (s:Stock)-[:TRADING_DAY]->(day)
WITH s, day
ORDER BY day.date ASC
WITH s, collect(day) as nodes, collect(day.close) as closes
SET s.close_array = closes
WITH nodes
CALL apoc.nodes.link(nodes, 'NEXT_DAY')
RETURN distinct 'done' AS result
股票节点增加收盘价数组属性
这是 Neo4j 浏览器中的示例某只股票的交易日链表可视化:
单个股票交易日之间的链表
我们将使用Pearson相似度[7]作为相关度量。上述研究论文的作者使用了更复杂的相关性指标,但这超出了本文的范围。
Pearson相似性算法的输入将是我们在上一步中生成的收盘价的有序列表。该算法将计算相关系数并将结果存储为相关股票之间的关系。我使用了topK参数值为3,因此每只股票将连接到三个最相关的股票。
MATCH (s:Stock)
WITH {item:id(s), weights: s.close_array} AS stockData
WITH collect(stockData) AS input
CALL gds.alpha.similarity.pearson.write({
data: input,
topK: 3,
similarityCutoff: 0.2
})
YIELD nodes, similarityPairs
RETURN nodes, similarityPairs
如前所述,该算法在股票代码节点之间产生了新的
SIMILAR
关系。
股票之间推断的相似性网络的子图
我们现在可以运行社区检测算法来识别多种相关股票社区,我决定在这个例子中使用Louvain社区检测算法[8]。社区 ID 将存储为节点属性。
CALL gds.louvain.write({
nodeProjection:'Stock',
relationshipProjection:'SIMILAR',
writeProperty:'louvain'
})
查看社区检测结果的最佳方法是生成可视化网络:
股票相似性社区结构的网络可视化
我不会详细解释可视化的社区结构,因为我们只查看了100个股票三个月时间跨度的数据。
按照研究论文的想法,您可能希望投资来自不同社区的股票,以分散您的风险并增加收益。您可以使用
线性回归斜率
从每个社区中挑选股票来构建投资组合并进行收益表现的回测。我发现有一个简单的线性回归模型apoc.math.regr程序[9]。不幸的是,开发人员在执行线性回归时考虑了不同的数据模型,因此我们首先必须调整图模型以适应过程的输入。在第一步中,我们向股票交易日节点添加一个辅助标签,以指示它所代表的股票。
MATCH (s:Stock)-[:TRADING_DAY]->(day)
CALL apoc.create.addLabels( day, [s.name]) YIELD node
RETURN distinct 'done'
向股票交易日节点添加一个辅助标签
接下来,我们需要计算x轴索引值。我们将简单地为每只股票的第一个交易日分配零的索引值,并在随后的每个交易日增加索引值。
MATCH (s:Stock)-[:TRADING_DAY]->(day)
WHERE NOT ()-[:NEXT_DAY]->(day)
MATCH p=(day)-[:NEXT_DAY*0..]->(next_day)
SET next_day.index = length(p)
交易日增加索引值
现在我们的图模型适合APOC中的线性回归过程的运算,我们可以继续计算拟合线的斜率值。在更严肃的情况下,我们可能希望调整收盘价,但在此演示中我们将跳过它。斜率值将存储为股票节点的属性。
MATCH (s:Stock)
CALL apoc.math.regr(s.name, 'close', 'index') YIELD slope
SET s.slope = slope;
斜率值存储为股票节点的属性
作为最后一步,我们可以推荐每个社区中表现最好的三只股票。
MATCH (s:Stock)
WITH s.louvain AS community, s.slope AS slope, s.name AS ticker
ORDER BY slope DESC
RETURN community, collect(ticker)[..3] as potential_investments
推荐每个社区中表现最好的三只股票
这不是投资建议,在投资之前请做你自己的研究。即便如此,在这篇博文中,我只查看了NASDAQ-100 股票的90天时间窗口,市场表现良好,因此在分散风险方面结果可能不是那么好。
如果您想更严谨一些,您可能需要收集更广泛的数据集并微调相关系数计算。不仅如此,简单的线性回归可能不是股票表现的最佳指标。另外,可以从Github[10]获取演示案例的源代码。
[1]
TOC: 通过图分析分散股票投资组合并降低风险增加收益
[2]
Diversify Your Stock Portfolio with Graph Analytics: https://medium.com/neo4j/diversify-your-stock-portfolio-with-graph-analytics-4520a5e46b3d
[3]
模式驱动的洞察:用Neo4j和Power BI可视化股票交易量相似性: https://medium.com/codex/pattern-driven-insights-visualize-stock-volume-similarity-with-neo4j-and-power-bi-13ca922acad1
[4]
金融市场风险的分散:最好投资外围市场: https://www.researchgate.net/publication/236185432_Spread_of_risk_across_financial_markets_Better_to_invest_in_the_peripheries
[5]
Kaggle的NASDAQ-100股票价格数据集: https://www.kaggle.com/datasets/kalilurrahman/nasdaq100-stock-price-data
[6]
Neo4j Sandbox: https://neo4j.com/sandbox/
[7]
Pearson相似度: https://neo4j.com/docs/graph-data-science/current/algorithms/similarity-functions/
[8]
Louvain社区检测算法: https://neo4j.com/docs/graph-data-science/current/algorithms/louvain/
[9]
线性回归模型apoc.math.regr程序: https://neo4j.com/labs/apoc/4.3/overview/apoc.math/apoc.math.regr/
[10]
Github: https://github.com/tomasonjo/blogs/tree/master/stock_diversity