
数据科学和机器学习(第 04 部分):预测当前股市崩盘
概述
在本系列文章的第 02 部分中,我们基于泰坦尼克号数据创建了一个简单的逻辑模型,今天我们将再构建一个逻辑模型,帮助我们预测市场崩盘。
在本文中,我们将通过建立股市崩盘的预测模型,对我们的逻辑模型进行有用的应用。为了测试我们的模型,我们将采用当前股市崩盘的测试数据,我认为这将与我们所有人相关。
股市崩盘
股市崩盘是指市场总价值的急剧快速下挫,价格通常在几天内下跌超过 10%。1987 年的黑色星期一和 2008 年的房地产泡沫就是股市崩盘的著名例子。 崩盘通常归因于价格泡沫的破裂,并归因于当大多数股市参与者试图抛售其资产时发生的大规模同时抛售。
在我们进一步讨论这件事之前,我想对这件事做一个免责声明:
这不是财会或交易建议。 希望您相信我不是巴菲特先生(Mr. buffet)或查理·芒格(Charlie Munger),也不是专业的股市投资者,我只是一名数据科学家,正在寻找一种将科学模型与交易联系起来的途径。请不要对本文内容过于较真,因为毕竟这些观点大部分都是从网上收集的,并且来自各种可信的来源链接到本文末尾的参考部分。在您决定使用本文中讨论的任何方法来制定交易决策之前,请自行研究相关文章。
现在我们有点跑题了,我们继续主题。
首先,我们看看影响股票价格的因素,一旦我们了解了这些因素,我们就有了基准点,因为这些因素可以作为我们的逻辑模型的数据(自变量)。
影响股票价格的因素
影响股票市场的因素很多,以下只是其中的几个。 请记住,从来没有一个明确的指标能清晰指明市场的行为方式,因此我将使用以下因素,
- 供给与需求
- 公司相关因素
- 利率
- 时事
- 通货膨胀
01: 供给与需求
影响股票市场的因素有很多,但如果您剔除所有外在因素,看看最基本的因素,那其实很简单,供需不平衡就会导致股票价格上涨和下跌。
如果苹果的产品突然缺货,就会有越来越多的人排队抢购,苹果的股价也会立即飙升。
与此类似,如果一家公司表现亮眼,每个人都想购买同一家公司的股票,那么就会出现股票短缺,导致一家公司股价暴涨;与此对比,如果股票滥发,但无人想买,则股价就会暴跌。
我们不可能(我也许说)获取我们在模型中使用的所有供求数据,既如此,我们就把这个因素留在数据集合中,但我相信任何能够准确获得这些数据的人,距离构建圣杯更近了一步。
02: 公司相关因素
公司内部发生的任何事情都将直接影响股价,如果公司在成长,随着产品的成功推出、收入的增加、债务的减少、以及投资者的大量涌入,那么公司的股价必然会上扬,因为每个人都想购买这家公司的股票,而这家公司正迈向一个又一个高峰
然而,如果一家公司出现亏损,产品出现故障,债务增加,那么大多数股东会希望抛售该公司的股票,从而拉低股价。
一个佐证这一观点很好的例子就是奈菲(Netflix)和苹果(Apple),
我们看到 Netflix 在 2022 年的前 3 个月内丢掉了超过 200,000 个服务订户,原因是一些会员受到价格上涨的制裁,以及公司内部发生的许多其它情况,这些情况直接导致 Netflix 的股价下跌。
另一方,Apple 在很长一段时间内一直是一家成功的公司,这是由于成功的产品发布、公司的良好领导、以及公司内部的其它积极因素,这些因素导致近年来股价涨势如虹。
为了判定公司的健康状况,我们将采用一个称为市盈率的指标
市盈率(Price-To-Earnings Ratio)
市盈率是用于衡量公司当前股价相对于每股收益(EPS)的估值。 市盈率可以用来衡量一家公司的健康程度。以下是基于 Apple 和 Netflix 股价和市盈率的图表
APPLE:
数据源: macrotrends.net
NETFLIX
数据源: macrotrends.net
如此看起来,市盈率在一年中每季度计算一次,因此在这种情况下,似乎这是所有免费数据源都可以提供的,我猜付费数据源可能更多。,我们也许会认为我们的数据有一些漏洞,这是由于我们需要在所有数据集的列中含有相同数量的行,以便针对模型的计算能有效工作,这是APPLEL 的数据:
如果数据是在一年的每个季度计算的,那么对于该季度的其余时间,我们在下一季度之前,将采用的相同数据进行预先计算,如此,在这种情况下,我们复制数据:
针对 NETFLIX 执行相同的操作。
03: 利率
联邦储备银行的一举一动直接影响股票价格,储备银行定期调整利率以稳定经济。 自然而然地,较高的利率意味着公司将为贷款不得不支付更多利息,导致纯利减少,这将反过来降低其股价;较低的利率意味着公司能以更低的成本从银行贷款,从而节省资金,并赚取更高的利润,在这种情况下,股票价格将上扬。
美联储最近正在加息,如此会打破需求平衡,迫使企业降低价格,最终帮助通胀下降。
从 2010 年到今天,美联储的基准利率图如下:
04: 时事
总体而言,全国或世界各地正在发生的事件也可能对股市产生巨大影响。没有人可以否认,2019 年末和 2020 年,新冠肺炎大流行对股市产生了非常强烈的负面影响,同年,美国发生了争取平等的骚乱,
影响股市价格的其它事件包括战争和恐怖袭击
所有这些事件都会导致股价大幅下跌,影响市场波动。
我不打算从这个因素中收集任何数据,因为它需要大量的工作和更多的模型来训练这些事件,这超出了我们在本系列文章中已经讨论的范畴。
05: 通货膨胀
通货膨胀是一种特定货币的购买力随着时间的推移而下降。 对购买力下降速度的量化估测,可以反映在一个经济体中一揽子选定商品和服务的平均价格水平在一段时间内上升。 一般价格水平的上涨通常以百分比表示,这意味着一种货币单位的实际购买量低于以前的时期。
此处可阅读更多有关通货膨胀的信息 https://www.investopedia.com/terms/i/inflation.asp
因此,基本上有两种类型的通货膨胀:核心 CPI 和 CPI:
- 核心 CPI - 除了能源和食品价格,所有的一切。
- CPI - 是经济内部的一切;能源、食品价格、教育、娱乐、等等。 存在于特定经济体的人们日常生活中的一切。
由于通货膨胀侵蚀了收益的一部分价值,市场很难衡量组成市场指数的那些公司的当前市值。 此外,随着公司调整,材料、库存和劳动力价格的上涨,都可能会影响收益。 结果造成,股票价格会波动,而这则导致波动。
好消息是,尽管美联储的紧缩政策可能会对固定收益投资产生负面影响,但股票在这些周期中通常表现良好。
看看 1970 年以来的美国 CPI 图表。
现在,我们收集所有必要的数据,并将它们存储在一个 CSV 文件之中。
从 Apple 开始:
收集数据
我们在 CSV 文件里收集的数据是核心 CPI、CPI、美联储基准利率、每股收益、和市盈率,我有所有这些数据。
我们的数据集中只剩下一个数据,那就是我们的因变量,但我们只有股票价格的原始值。我们创建一个脚本,它可以告诉我们某个特定月份是否发生了股市崩盘
CrashClassifyScript.mq5 内部
void DetectCrash(double &prices[], int& out_binary[]) { double prev_high = prices[0]; ArrayResize(out_binary,ArraySize(prices)-1); //we reduce the size by one since we ignore the current we predict the previous one for (int i=1; i<ArraySize(prices); i++) { int prev = i-1; if (prices[i] >= prev_high) prev_high = prices[i]; //grab the highest price double percent_crash = ((prev_high - prices[i]) / prev_high) * 100.0; //convert crash to percentage printf("crash percentage %.2f high price %.4f curr price %.4f ", percent_crash,prev_high,prices[i]); //based on the definition of a crash; markets has to fall more than 10% percent if (percent_crash > 10) out_binary[prev] = 0; //downtrend (crash) else out_binary[prev] = 1; //uptrend (no crash ) } }
如果您留意到第一个 prev_high,您会注意到,我已给它赋予上一个价格的数值,这是因为我复制了 2009 年 12 月 1 日的苹果股价,替代 2010 年 1 月 1 日。我希望有一个空间在第一次计算时检测崩溃,然后加上该月份,这已经成为可能,但我们忽略了输出数据集的那个月,因为我们不再需要它,这就是为什么内部的 out_binary[prev] 索引 prev 基本上是 i-1,因为我们从索引 1 开始循环。
以下是打印输出二进制数组时的输出
CrashClassifyScript DATE 1/1/2010 TREND 1
CrashClassifyScript DATE 2/1/2010 TREND 1
.........
CrashClassifyScript DATE 4/1/2022 TREND 0
CrashClassifyScript DATE 5/1/2022 TREND 0
将所有数据列添加到 excel 中的一个 csv 文件中,将生成如下所示的 csv 文件
太棒了,现在一切都准备就绪,我们开始处理更多的代码。
我们都知道,在我们的逻辑模型背后,有一个线性回归算法,我们可以在线性模型中使用任何数据之前,我们必须检查它是否与其自变量相关。我们调用我在上一篇文章中创建的线性回归库中添加的方法 Corrceff 来检查它。
TestScript.mq5 内部
m_lr = new CMatrixRegression; Print("Matrix multiple regression"); m_lr.Init(8,"2,4,5,6,7",file_name,",",0.7); m_lr.corrcoeff(); m_lr.MultipleMatLinearRegMain(); delete m_lr;
输出肯定是:
Matrix multiple regression
TestScript Init, number of X columns chosen =5
TestScript "2" "4" "5" "6" "7"
TestScript All data Array Size 740 consuming 52 bytes of memory
TestScript Correlation Coefficients
TestScript Independent Var Vs Trend = 0.225
TestScript Independent Var Vs CPI = -0.079
TestScript Independent Var Vs Core CPI = -0.460
TestScript Independent Var Vs EPS($) = -0.743
TestScript Independent Var Vs PE Ratio = -0.215
我刚刚在不同地方收集的所有数据似乎都与股票价格无关,尽管很多人在网上叫嚣这些是影响股票市场的因素,而我的理解是,消息来源最初给出了一个免责声明,即没有明确的指标表明市场是如何运作的,但线性模型的数字揭示出一个非常不同的故事,例如,CPI 与 Apple 的股价,我本以为这里会有非常强的负相关性,但表现出的则是相关性很弱,无法用于线性回归,只有核心 CPI 显示出约 -0.46 的负相关性。其中最强的是每股收益(EPS),其负相关性约为 0.743,可转换为 -74.3%。
我们不能止步于此,在 python 中可视化数据并亲自查看是非常重要的,以防我们在数字中遗漏了一些东西,或者我们的计算不通顺:

输出
我认为,在这一点上,很明显,我们收集的大多数数据之间没有太大的联系,我们把数据过滤一遍,
我们只用三个独立变量来建立我们的模型,
- 核心CPI(相关性为 -46%,近乎一半)
- EPS(相关系数约为 -74.2%,所有数据当中的最佳相关)
- 最后,联邦储备银行基准利率(相关性约 -33% ,相关性最低。当您构建一个严谨的模型时,我不建议这个)。
好的,现在我们只用所需的列来初始化函数库:
log_reg.Init(file_name,delimiter,2,"3,5,6",0.7);
对于那些错过了逻辑回归基本功能的人,应参考这篇文章。
函数库的进一步改进
//These should be called before the Init void FixMissingValues(string columns); void LabelEncoder(string columns, string members);
逻辑模型对缺失值很敏感,因为它是一种分类机器学习模型,它将零数据视为一个已分类的类别,这也许表明数据缺失。它还可以将 nan 值和字符串视为零,这取决于我们如何读取 MQL5 中的文件,这就是为什么我对函数库做了一些改进,
用均值替换缺失值的函数,和将字符串编码成标签的函数,
这些函数应该在 Init 函数之前调用
现在,我们的逻辑库继承了我们在上一篇文章中创建的矩阵回归函数库的组件。
class CLogisticRegression: protected CMatrixRegression
我们进入最好的部分,看看我们的模型有多好,
输出为:
Confusion Matrix [ 0 13 ] [ 0 31 ] Tested model accuracy =0.7045
基于测试数据集,我们的模型精度为 70.45%,😲 此时我目瞪口呆。
我想,由于我之前的数据缺陷,我甚至不能达到 50% 的目标,我想在某个时候一定会有错误,直到我尝试用 python 的相同方法来获得相同的结果。
B A M
请记住,我们的因变量是我们在本文早期的脚本中收集的趋势列,用于检测崩盘;价格列仅用于显示线性模型的相关系数;因为我们不能使用分别表示下跌和上涨趋势的二进制值 0 和 1 来找到相关性。在这种实例中,它是股票的真实价格
现在,我们将焦点转移到 NETFLIX。
此处,这位兄弟的相关系数是这个样子的,
Correlation Coefficients Independent Var Vs Trend = 0.071 Independent Var Vs rate (FEDs rate) = 0.310 Independent Var Vs CPI = 0.509 Independent Var Vs Core CPI = 0.607 Independent Var Vs EPS = 0.917 Independent Var Vs PE Ratio = -0.213
我们在下面讨论的大多数因素似乎都对 NETFLIX 产生正面影响,负面影响只有市盈率,最强的因素是每股收益,与股价的相关性约为 92%,其它因素是核心 CPI 和 CPI,因此对于 NETFLIX,我们将仅用三个数据来构建模型:
- EPS
- 核心 CPI
- 和 CPI
我们再次可视化我们的数据。
在 NETFLIX 上看起来比上次在 Apple 上好多了,
长话短说,
log_reg = new CLogisticRegression(); Print("NETFLIX"); file_name = "Netflix Dataset.csv"; log_reg.Init(file_name,delimiter,2,"4,5,6",0.7); log_reg.LogisticRegressionMain(accuracy); printf("Tested model accuracy =%.4f",accuracy); delete log_reg;
输出
FN 0 07:54:45.106 TestScript NETFLIX PN 0 07:54:45.108 TestScript ==== TRAINED LINEAR REGRESSION MODEL COEFFICIENTS ==== ED 0 07:54:45.108 TestScript [ RO 0 07:54:45.108 TestScript 1.43120 -0.05632 -0.54159 0.48957 EE 0 07:54:45.108 TestScript ] CQ 0 07:54:45.108 TestScript columns = 4 rows = 1 PH 0 07:54:45.108 TestScript ========= LINEAR REGRESSION MODEL TESTING STARTED ========= QP 0 07:54:45.108 TestScript Tested Linear Model R square is = -0.35263665822405277 GR 0 07:54:45.108 TestScript Confusion Matrix EE 0 07:54:45.108 TestScript [ 0 18 ] HN 0 07:54:45.108 TestScript [ 0 26 ] MJ 0 07:54:45.108 TestScript Tested model accuracy =0.5909
尽管有与股价具有强线性相关性的数据, NETFLIX 模型的精度低于60%,其精度比之 Apple 模型的精度约为 70%。您可以自己处理数据集的其余部分,并查看模可能的外观。
实时股票市场测试
为了能够在我们的智能系统内部进行实时市场测试,我们需要对我们的主要逻辑回归函数进行一些修改,我们需要令该函数将预测值及其各自的日期存储在 CSV 文件中,我们将在策略测试器中提取该文件,依据我们的模型推出信号指明市场走向。
下面是我们将如何收集数据,并将其存储到 csv 文件当中:
WriteToCSV(TestPredicted,dates,"Predicted "+m_filename,m_delimiter);
记住,我们只收集测试数据集结果。
以下是数据如何存储在 csv 文件中的简要视图:
NETFLIX Predicted, date_time 1,8/1/2018 1,9/1/2018 1,10/1/2018 1,11/1/2018 1,12/1/2018 1,1/1/2019 APPLE Predicted, date_time 1,9/1/2018 1,10/1/2018 1,11/1/2018 1,12/1/2018 1,1/1/2019 1,2/1/2019
如果您留意到混淆矩阵部分,您会注意到我们的模型针对上升趋势具有良好预测,TP(在矩阵中有大量矩阵行真阳)。
实时股票价格测试 EA
创建 EA 的第一步是从 CSV 文件中收集数据,但在此之前,我们希望让策略测试器知道我们将在测试时用到此文件。
#property tester_file "Predicted Apple Dataset.csv"
现在,简要介绍一下我在OnInit 函数上编码和调用的函数
GetColumnDatatoArray(1,Trend); GetColumnDatatoArray(2,dates);
这些函数非常常见,我们在函数库中用到了很多,基本上我们从第一列中收集数据,然后将它们存储到Trend[] 数组中,对于dates[] 数组的处理过程相同。
下一件重要的事情是将我们从 csv 文件中收集的时间转换为标准时间格式,该格式可被 MQL5 所理解
ConvertTimeToStandard();
下面是该函数的内部内容:
void ConvertTimeToStandard() { // A one time attempt to convert the date to yy.mm.dd ArrayResize(date_datetime,ArraySize(dates)); for (int i=0; i<ArraySize(dates); i++) { StringReplace(dates[i],"/","."); //replace comma with period in each and every date //Print(dates[i]); string mm_dd_yy[]; ushort sep = StringGetCharacter(".",0); StringSplit(dates[i],sep,mm_dd_yy); //separate month, day and year //Print("mm dd yy date format"); //ArrayPrint(mm_dd_yy); string year = mm_dd_yy[2]; string day = mm_dd_yy[1]; string month = mm_dd_yy[0]; dates[i] = year+"."+month+"."+day; //store to a yy.mm.dd format date_datetime[i] = StringToTime(dates[i]); //lastly convert the string datetime to an actual date and time } }
这些是我认为值得做出解释的函数,在 Init() 函数中它们做了什么。
下一步是在 Ontick 函数上测试模型预测,这是我们的智能系统的支柱:
datetime today[1]; int trend_signal = -1; //1 is buy signal 0 is sell signal CopyTime(Symbol(),PERIOD_D1,0,1,today); if (isNewBar()) for (int i=0; i<ArraySize(date_datetime); i++) { if (today[0] == date_datetime[i]) //train in that specific day only { if ((int)Trend[i] == 1) trend_signal = 1; else trend_signal = 0; // close all the existing positions since we are coming up with new data signals ClosePosByType(POSITION_TYPE_BUY); ClosePosByType(POSITION_TYPE_SELL); break; } if (MQLInfoInteger(MQL_TESTER) && today[0] > date_datetime[ArrayMaximum(date_datetime)]) { Print("we've run out of the testing data, Tester will be cancelled"); ExpertRemove(); } } //--- Time to trade MqlTick tick; SymbolInfoTick(Symbol(),tick); double ask = tick.ask , bid = tick.bid; //--- if (trend_signal == 1 && PositionCounter(POSITION_TYPE_BUY)<1) { m_trade.Buy(Lots,Symbol(),ask,0,0," Buy trade "); ClosePosByType(POSITION_TYPE_SELL); //if the model predicts a bullish market close all sell trades if available } if (trend_signal == 0 && PositionCounter(POSITION_TYPE_SELL)<1) { m_trade.Sell(Lots,Symbol(),bid,0,0,"Sell trade"); ClosePosByType(POSITION_TYPE_BUY); //vice versa if the model predicts bear market } }
我选择在指定那一天,并在 NewBar 事件句柄处训练模型的主要原因是为了降低测试应用程序的成本,为了进一步降低成本,我还硬编码了一个条件,即一旦测试数据集耗尽,策略测试器应立即停止。
就是这样了,查看下面链接的完整代码,现在到了在策略测试器中测试模型的时候了。
APPLE 测试结果
图形
Netflix 是另一方面,测试报告
测试图形
太棒了,正如您所看到的,Apple 模型的准确率约为 70%,与竞争对手 NETFLIX 相比,到目前为止,它已经做出了一个很好的预测模型,在策略测试器上有一个漂亮的图表。
底线
逻辑模型的好处是,它们易于构建和训练,且它们在分类数据方面做得很出色,尽管在我们的模型中查找数据是不应该被视为理所当然的,因为这是最关键的步骤之一,一旦出错,可能会导致模型效率低下。
尽管如此,您仍然可以对我们的函数库进行更多改进,并再次收集数据,因为我仍然相信,我收集数据并在 Crashclassify 脚本中对其进行分类的方式并不是观察崩盘的有效方法,无论如何,这是为了阅读。
本文的 Github 存储库链接在这里 > https://github.com/MegaJoctan/LogisticRegression-MQL5-and-python。
本文由MetaQuotes Ltd译自英文
原文地址: https://www.mql5.com/en/articles/10983


