META(原FACEBOOK)股票数据分析

886 阅读15分钟

从Yahoo Fiance 下载meta公司股票数据,先进行分析。后使用SVM、随机森林、XGBOOST等进行预测。使用python进行编程。

import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.preprocessing import StandardScaler
from sklearn.svm import SVC
from sklearn.metrics import classification_report, confusion_matrix

# 加载数据集
data = pd.read_csv('datasets/META.csv') #数据从2012-05-18到2024-06-03
data.head(5)

image.png

列名分别是日期、开盘价、最高价、最低价、收盘价、调整后收盘价(考虑了所有可能影响股票价格的公司行为,比如分红、拆股、配股等。调整后收盘价更准确地反映了股票的实际价值变化),交易量。我们首先对数据进行可视化分析

import matplotlib.pyplot as plt

# 读取股票数据
df = pd.read_csv('datasets/META.csv')

# 确保日期列为日期格式
df['Date'] = pd.to_datetime(df['Date'])

# 设置日期列为索引
df.set_index('Date', inplace=True)

# 计算每日收益率
df['Return'] = df['Adj Close'].pct_change()

# 添加时间周期特征
df['Year'] = df.index.year
df['Month'] = df.index.month
df['Day'] = df.index.day
df['Weekday'] = df.index.weekday  # 0=Monday, 1=Tuesday, ..., 6=Sunday

# 按时间周期计算平均收益率
year_return = df.groupby('Year')['Return'].mean()
monthly_return = df.groupby('Month')['Return'].mean()
weekday_return = df.groupby('Weekday')['Return'].mean()

# 创建1x3的子图网格
fig, axes = plt.subplots(1, 3, figsize=(18, 5))

# 绘制年度平均收益率
axes[0].bar(year_return.index, year_return.values)
axes[0].set_title('Average Yearly Return')
axes[0].set_xlabel('Year')
axes[0].set_ylabel('Average Return')
axes[0].grid(True)

# 绘制月度平均收益率
axes[1].bar(monthly_return.index, monthly_return.values)
axes[1].set_title('Average Monthly Return')
axes[1].set_xlabel('Month')
axes[1].set_ylabel('Average Return')
axes[1].grid(True)

# 绘制每周每日平均收益率
axes[2].bar(weekday_return.index, weekday_return.values)
axes[2].set_title('Average Weekday Return')
axes[2].set_xlabel('Weekday')
axes[2].set_ylabel('Average Return')
axes[2].set_xticks(np.arange(7))
axes[2].set_xticklabels(['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'])
axes[2].grid(True)

# 调整布局
plt.tight_layout()

# 显示图形
plt.show()

image.png

画出年月日的平均收益率。从年平均日收益率,也就是第一幅图,2012年,2018年,2022年,三年的平均日收益率是负的。我们逐年来分析:

2012年facebook首次公开募股(IPO),虽然IPO初期市场反应热烈,但随后出现了一系列问题,包括交易技术故障、对公司估值过高的质疑、股票供应过剩等,导致股价在IPO后不久大幅下跌。IPO后的几个月内,Facebook股价曾一度跌至约17美元,远低于发行价。投资者对Facebook的盈利能力和长期商业模式持怀疑态度。虽然Facebook拥有庞大的用户基础,但其如何有效地将用户流量转化为可持续的收入模式还不明朗。

2018年经历了多个影响其股价的重要事件,导致全年股票收益率为负。以下是一些关键事件:剑桥分析数据丑闻(Cambridge Analytica Scandal),2018年3月,披露剑桥分析公司(Cambridge Analytica)不当获取并利用了约8700万Facebook用户的数据用于政治广告投放,包括2016年美国总统大选。这一丑闻严重损害了Facebook的声誉,引发了公众和监管机构对数据隐私和安全的强烈关注。Facebook的股价在事件爆发后迅速下跌。欧洲通用数据保护条例(GDPR),2018年5月,欧洲实施了《通用数据保护条例》(GDPR),要求公司对用户数据的收集和使用更加透明,并对违规行为实施高额罚款。GDPR对Facebook的业务运营产生了重大影响,迫使其改进数据保护措施,可能增加了运营成本并影响用户增长和广告收入。

2022年前夕,Meta Platforms在2021年末宣布了重大的战略转型,全面进军元宇宙领域。然而,这一转型需要巨额投资,包括研发和基础设施建设。大量投资元宇宙带来了财务压力,短期内对利润造成负面影响,投资者对此表示担忧,导致股价下跌。2022年全球经济不确定性增加,包括通货膨胀上升、美联储加息和地缘政治紧张局势,这些因素都对整体市场情绪造成了负面影响。同时面对TikTok的崛起。

同时第三幅图,一周中的每天的平均日收益,周一日收益偏低,周三却异常的高,周五又偏低,有过股票基金交易经历的肯定深有体会。

可能的原因

  1. 市场情绪和交易行为:

    • 一些交易者可能在周一和周二对市场做出初步反应,然后在周三调整他们的头寸。
    • 周三可能是机构投资者重新平衡或调整投资组合的日子。
  2. 经济数据和报告:

    • 许多经济报告和公司财报会在一周中间发布,特别是周三。这些报告会对市场产生重大影响。
  3. 周末效应和周中效应:

    • 传统的周末效应假说认为周五和周一的波动可能较大,而周中的交易可能较为稳定。
    • 周一和周二的市场活动可能更多地受到周末新闻和事件的影响,而周三的市场行为可能反映了更稳定的趋势。
  4. 技术分析和市场策略:

    • 一些交易策略可能更倾向于在周三进行买入或卖出操作,从而影响市场走势。

进一步通过我们已有的数据,看是否能解释这个现象,进行一个方差分析,使用ANOVA检验不同星期几的收益率是否有显著差异。

import matplotlib.pyplot as plt
import seaborn as sns
from scipy import stats

# 统计检验 - ANOVA
returns_by_weekday = [df[df['Weekday'] == i]['Return'].dropna().values for i in range(5)]
f_stat, p_value = stats.f_oneway(*returns_by_weekday)
print(f"ANOVA F-statistic: {f_stat}, p-value: {p_value}")

# 进一步分析周三的收益率分布
wednesday_returns = df[df['Weekday'] == 2]['Return'].dropna()

# 绘制周三收益率分布
plt.figure(figsize=(6, 4))
sns.histplot(wednesday_returns, kde=True)
plt.title('Distribution of Wednesday Returns')
plt.xlabel('Return')
plt.ylabel('Frequency')
plt.grid(True)
plt.show()

image.png

  • F-statistic: ANOVA中的F值表示组间方差与组内方差的比率。在此案例中,F值为1.7881,表示不同工作日之间的收益率差异不大。

  • p-value: p值表示观察到的结果在零假设(即不同工作日的平均收益率没有显著差异)下出现的概率。在此案例中,p值为0.1284,这大于常用的显著性水平(如0.05)。因此,我们不能拒绝零假设,说明不同工作日之间的收益率没有显著差异。

尽管初步的ANOVA结果没有显示显著差异,但通过更深入的分析,通过获取更多的数据(经济数据和事件分析:分析每周不同日期发布的重要经济数据和公司新闻,查看是否存在相关性),可能会揭示出潜在的市场特征和规律。

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

# 加载数据
df = pd.read_csv('datasets/META.csv', index_col='Date', parse_dates=True)

# 只保留2020年以后的数据
df = df[df.index >= '2020-01-01']

# 计算RSI
def calculate_rsi(data, window):
    delta = data.diff()
    gain = (delta.where(delta > 0, 0)).rolling(window=window).mean()
    loss = (-delta.where(delta < 0, 0)).rolling(window=window).mean()
    rs = gain / loss
    rsi = 100 - (100 / (1 + rs))
    return rsi

df['RSI'] = calculate_rsi(df['Close'], 14)

# 计算布林带
df['SMA'] = df['Close'].rolling(window=20).mean()
df['Upper Band'] = df['SMA'] + 2 * df['Close'].rolling(window=20).std()
df['Lower Band'] = df['SMA'] - 2 * df['Close'].rolling(window=20).std()

# 绘制RSI和布林带
plt.figure(figsize=(14, 7))

# 绘制RSI
plt.subplot(2, 1, 1)
plt.plot(df.index, df['RSI'], label='RSI', color='purple')
plt.axhline(y=70, color='red', linestyle='--')
plt.axhline(y=30, color='green', linestyle='--')
plt.title('Relative Strength Index (RSI)')
plt.xlabel('Date')
plt.ylabel('RSI')
plt.legend()
plt.grid(True)

# 绘制布林带
plt.subplot(2, 1, 2)
plt.plot(df.index, df['Close'], label='Close Price', color='blue')
plt.plot(df.index, df['SMA'], label='20-Day SMA', color='orange')
plt.plot(df.index, df['Upper Band'], label='Upper Band', color='green')
plt.plot(df.index, df['Lower Band'], label='Lower Band', color='red')
plt.fill_between(df.index, df['Upper Band'], df['Lower Band'], color='grey', alpha=0.3)
plt.title('Bollinger Bands')
plt.xlabel('Date')
plt.ylabel('Price')
plt.legend()
plt.grid(True)

plt.tight_layout()
plt.show()

image.png

RSI是一种动量振荡指标,用于衡量股票价格的变化速度和变化幅度,以识别超买或超卖的情况。超买区域,当 RSI 超过 70 时,表示股票可能处于超买状态,价格可能会回落。超卖区域,当 RSI 低于 30 时,表示股票可能处于超卖状态,价格可能会上涨。 从图中可以看出基本符合这个规律。

布林带是一种波动性指标,由一个中间的简单移动平均线(SMA)和两条上下波动范围带(标准差)组成,用于反映价格的波动性。

接下来,我们使用机器学习进行预测,首先我们使用除收盘价以外的因子来做影响因子(特征),收盘价作为目标。首先使用支持向量机来做分类,当天相较于前一天收盘价下降就是下跌,反之上涨,所以可以做二分类,核函数选径向基函数。

data['Date'] = pd.to_datetime(data['Date'])

# 创建一个新特征'Price Change',表示每天的价格变化
data['Price Change'] = data['Close'].diff()

# 创建一个目标变量'Label',表示价格是上涨(1)还是下跌(0)
data['Label'] = np.where(data['Price Change'] > 0, 1, 0)
# 去掉缺失值
data.dropna(inplace=True)

# 选择特征和目标变量
features = data[['Open', 'High', 'Low', 'Close', 'Adj Close', 'Volume']]
labels = data['Label']

# 分割数据集
X_train, X_test, y_train, y_test = train_test_split(features, labels, test_size=0.3, random_state=42)

# 标准化数据
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

# 初始化SVM模型
svm_model = SVC(kernel='rbf', C=1, gamma='scale')

# 训练模型
svm_model.fit(X_train_scaled, y_train)

# 预测
y_pred = svm_model.predict(X_test_scaled)

# 评估模型
print(confusion_matrix(y_test, y_pred))
print(classification_report(y_test, y_pred))

image.png

左上角为混淆矩阵,同时观察到较低的精确度。可见分类结果很差。我们使用网格搜索进行参数优化。

from sklearn.model_selection import GridSearchCV

# 定义参数网格
param_grid = {
    'C': [0.1, 1, 10, 100],
    'gamma': [1, 0.1, 0.01, 0.001],
    'kernel': ['rbf']
}

# 使用网格搜索进行参数调优
grid_search = GridSearchCV(SVC(), param_grid, refit=True, verbose=2)
grid_search.fit(X_train_scaled, y_train)

# 打印最佳参数
print("Best Parameters:", grid_search.best_params_)

# 使用最佳参数进行预测
best_model = grid_search.best_estimator_
y_pred_best = best_model.predict(X_test_scaled)

# 评估最佳模型
print(confusion_matrix(y_test, y_pred_best))
print(classification_report(y_test, y_pred_best))

image.png

准确率上升到0.8左右,是一个可以接受的结果。

接着使用随机森林来做分类,对比一下两种方法的性能如何。


from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import GridSearchCV

# 使用随机森林进行参数调优
param_grid_rf = {
    'n_estimators': [100, 200, 300],
    'max_depth': [10, 20, 30],
    'min_samples_split': [2, 5, 10],
    'min_samples_leaf': [1, 2, 4]
}

grid_search_rf = GridSearchCV(RandomForestClassifier(), param_grid_rf, refit=True, verbose=2, cv=5)
grid_search_rf.fit(X_train_scaled, y_train)

# 打印最佳参数
print("Best Parameters (Random Forest):", grid_search_rf.best_params_)

# 使用最佳参数进行预测
best_model_rf = grid_search_rf.best_estimator_
y_pred_rf = best_model_rf.predict(X_test_scaled)

# 评估最佳模型
print(confusion_matrix(y_test, y_pred_rf))
print(classification_report(y_test, y_pred_rf))

image.png

可见即使进行参数优化的随机森林在该数据集上,准确率低于支持向量机。

接下来,我们做预测,使用SVM回归模型、随机森林回归模型、XGBoost回归模型。代码分别如下:

import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.svm import SVR
from sklearn.metrics import mean_squared_error, mean_absolute_error


# 按年份划分数据
train_data = df[df.index < '2024-05-01']
test_data = df[df.index >= '2024-05-01']

# 特征和标签
features = ['Open', 'High', 'Low', 'Volume']
label = 'Close'

X_train = train_data[features]
y_train = train_data[label]

X_test = test_data[features]
y_test = test_data[label]

# 标准化数据
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

# 训练SVM回归模型
svm = SVR(kernel='rbf', C=1, gamma='scale')
svm.fit(X_train_scaled, y_train)

# 预测
y_pred = svm.predict(X_test_scaled)

# 评估
mse = mean_squared_error(y_test, y_pred)
mae = mean_absolute_error(y_test, y_pred)
print(f'Mean Squared Error: {mse}')
print(f'Mean Absolute Error: {mae}')

# 绘制结果
plt.figure(figsize=(14, 7))
plt.plot(test_data.index, y_test, label='Actual', color='b')
plt.plot(test_data.index, y_pred, label='Predicted', color='r')
plt.title('Stock Price Prediction')
plt.xlabel('Date')
plt.ylabel('Price')
plt.legend()
plt.grid(True)
plt.show()

image.png

import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.preprocessing import StandardScaler
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import mean_squared_error, mean_absolute_error

# 按年份划分数据
train_data = df[df.index < '2024-05-01']
test_data = df[df.index >= '2024-05-01']


features = ['Open', 'High', 'Low', 'Volume']
label = 'Close'

X_train = train_data[features]
y_train = train_data[label]

X_test = test_data[features]
y_test = test_data[label]

# 标准化数据
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

# 使用随机森林回归模型
rf = RandomForestRegressor()

# 网格搜索调优参数
param_grid = {
    'n_estimators': [100, 200, 300],
    'max_depth': [10, 20, 30],
    'min_samples_split': [2, 5, 10]
}

grid_search = GridSearchCV(estimator=rf, param_grid=param_grid, cv=5, n_jobs=-1, verbose=2)
grid_search.fit(X_train_scaled, y_train)

# 使用最佳参数训练模型
best_rf = grid_search.best_estimator_
best_rf.fit(X_train_scaled, y_train)

# 预测
y_pred = best_rf.predict(X_test_scaled)

# 评估
mse = mean_squared_error(y_test, y_pred)
mae = mean_absolute_error(y_test, y_pred)
print(f'Mean Squared Error: {mse}')
print(f'Mean Absolute Error: {mae}')

# 绘制结果
plt.figure(figsize=(14, 7))
plt.plot(test_data.index, y_test, label='Actual', color='b')
plt.plot(test_data.index, y_pred, label='Predicted', color='r')
plt.title('Stock Price Prediction')
plt.xlabel('Date')
plt.ylabel('Price')
plt.legend()
plt.grid(True)
plt.show()

image.png

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import mean_squared_error, mean_absolute_error
import xgboost as xgb

# 假设已经加载股票数据到DataFrame
# df = pd.read_csv('path_to_your_stock_data.csv', parse_dates=['Date'])
# df.set_index('Date', inplace=True)

# 按日期划分数据
train_data = df[df.index < '2024-05-01']
test_data = df[df.index >= '2024-05-01']

# 特征和标签
features = ['Open', 'High', 'Low', 'Volume']
label = 'Close'

X_train = train_data[features]
y_train = train_data[label]

X_test = test_data[features]
y_test = test_data[label]

# 标准化数据
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

# 使用XGBoost回归模型
xg_reg = xgb.XGBRegressor(objective='reg:squarederror', colsample_bytree=0.3, learning_rate=0.1, max_depth=5, alpha=10, n_estimators=100)
xg_reg.fit(X_train_scaled, y_train)

# 预测
y_pred = xg_reg.predict(X_test_scaled)

# 评估
mse = mean_squared_error(y_test, y_pred)
mae = mean_absolute_error(y_test, y_pred)
print(f'Mean Squared Error: {mse}')
print(f'Mean Absolute Error: {mae}')

# 绘制结果
plt.figure(figsize=(14, 7))
plt.plot(test_data.index, y_test, label='Actual', color='b')
plt.plot(test_data.index, y_pred, label='Predicted', color='r')
plt.title('Stock Price Prediction')
plt.xlabel('Date')
plt.ylabel('Price')
plt.legend()
plt.grid(True)
plt.show()

image.png

从三张图,可见随机森林回归模型和xgboost回归模型的效果较好,在一个月的时间跨度上,预测结果基本吻合,我同时测试了在三个月和一年的时间长度进行预测,效果基本在前一个月较好,一个月后预测开始失效。SVM回归在该数据集,以及当前参数设定下,预测效果不佳。在代码中可以看到,这里做预测,是使用了除收盘价以外的因子来做预测的。而真实的未来股价预测,这些数据肯定没有的。我们使用ARIMA模型(时间序列预测)来进行做预测。

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from statsmodels.tsa.arima.model import ARIMA
from sklearn.metrics import mean_squared_error, mean_absolute_error
import warnings
warnings.filterwarnings('ignore')

# 假设已经加载股票数据到DataFrame
# df = pd.read_csv('path_to_your_stock_data.csv', parse_dates=['Date'])
# df.set_index('Date', inplace=True)

# 准备训练数据和测试数据
train_data = df[df.index < '2024-05-01']
test_data = df[(df.index >= '2024-05-01') & (df.index < '2024-06-01')]

# 提取收盘价作为时间序列
ts_train = train_data['Close']
ts_test = test_data['Close']

# 拟合ARIMA模型
model = ARIMA(ts_train, order=(5, 1, 0))  # (p,d,q)参数可以通过AIC/BIC准则选择最佳值
model_fit = model.fit()

# 预测2024年5月的股价
start = len(ts_train)
end = start + len(ts_test) - 1
forecast = model_fit.predict(start=start, end=end, typ='levels')

# 评估模型性能
mse = mean_squared_error(ts_test, forecast)
mae = mean_absolute_error(ts_test, forecast)
print(f'Mean Squared Error: {mse}')
print(f'Mean Absolute Error: {mae}')

# 绘制结果,包含测试数据的前一个月和测试的当月
plt.figure(figsize=(7, 4))
# 绘制测试数据的前一个月
plt.plot(train_data[-30:].index, train_data['Close'][-30:], label='Train Data (Previous Month)', color='blue')
# 绘制测试数据
plt.plot(ts_test.index, ts_test, label='Actual', color='green')
plt.plot(ts_test.index, forecast, label='Predicted', color='red')
plt.title('Stock Price Prediction for May 2024')
plt.xlabel('Date')
plt.ylabel('Price')
plt.legend()
plt.grid(True)
plt.show()

image.png

可见不出意外的,预测结果很差,我们使用的数据过于单薄,无法支撑该一预测。股票价格的预测是十分复杂的。

1. 技术分析

技术分析通过分析历史价格和交易量数据来预测未来价格走势。常用的方法和工具包括:

  • 移动平均线(MA):用于平滑价格数据,识别价格趋势。
  • 相对强弱指数(RSI):衡量价格的变化速率,识别超买或超卖状态。
  • 布林带(Bollinger Bands):利用价格波动性设置价格目标区间。
  • MACD(平滑异同移动平均线):用于识别趋势变化和价格反转点。

2. 基本面分析

基本面分析通过评估公司的财务状况、行业前景和宏观经济因素来预测股价。常用的方法包括:

  • 财务报表分析:分析公司资产负债表、利润表和现金流量表。
  • 比率分析:如市盈率(P/E)、市净率(P/B)、股息收益率等。
  • 宏观经济指标:如GDP增长率、通货膨胀率、利率等。

3. 量化分析

量化分析通过构建数学模型和算法来预测股价,常用的方法包括:

  • 时间序列分析:如ARIMA、GARCH等模型。
  • 机器学习和深度学习:如支持向量机(SVM)、随机森林(Random Forest)、长短期记忆网络(LSTM)等。
  • 因子模型:如Fama-French三因子模型,考虑市场、规模和价值等因子。

4. 大数据和人工智能

大数据和人工智能技术越来越多地应用于股价预测。常用的方法包括:

  • 自然语言处理(NLP):分析新闻、社交媒体和公司公告等文本数据,以获取市场情绪和事件信息。
  • 社交网络分析:分析投资者和市场参与者的互动数据。
  • 机器学习集成模型:如集成多个预测模型,提升预测准确性。

5. 组合预测

商业机构通常不会单一使用上述某一种方法,而是结合多种方法进行综合预测,以期获得更全面和准确的结果。例如:

  • 结合技术分析和基本面分析:利用技术分析捕捉短期价格波动,利用基本面分析识别长期投资机会。
  • 多模型组合:集成时间序列模型、机器学习模型和深度学习模型,综合各自的优势。