You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

请求基于Twitter情感分析的EURUSD涨跌预测项目代码架构建议

EURUSD推特情感预测涨跌:代码结构与特征选择实战建议

特征选择:优先用当日情感聚合特征,而非单条推特

直接用单条推特作为特征几乎不可行,原因很明确:

  • 单条推特噪声极大:水军、无关闲聊、个人情绪化发言会严重干扰模型,且单条内容无法代表市场整体态度。
  • 时序维度不匹配:你要预测的是次日日度涨跌,单条推特的分钟/小时级粒度和目标变量的日度粒度脱节,模型无法建立有效映射关系。

更务实的做法是对当日所有推特做情感聚合统计,常用的有效特征包括:

  • 基础统计:当日所有推特的情感得分均值、中位数、标准差(标准差能反映市场情绪的分歧程度)
  • 分类占比:正面/负面/中性推特的占比,比如当日负面推特占60%,可能预示下跌
  • 加权聚合:给高影响力用户(认证交易员、财经媒体、大V)的情感得分加权重(比如按粉丝数或账号影响力赋值),这类用户的观点对市场实际影响更大

代码结构模块化规划

把项目拆成5个独立模块,便于维护和迭代:

1. 推特爬取模块

用snscrape封装成可复用函数,指定关键词、时间范围,爬取每条推特的核心字段:

import snscrape.modules.twitter as sntwitter
import pandas as pd

def scrape_eurusd_tweets(start_date, end_date):
    tweets_list = []
    # 构造搜索query,过滤转发、指定英文内容
    query = f"EURUSD lang:en since:{start_date} until:{end_date} -filter:retweets"
    for i, tweet in enumerate(sntwitter.TwitterSearchScraper(query).get_items()):
        tweets_list.append({
            "date": tweet.date.date(),  # 只保留日期,方便后续按日聚合
            "content": tweet.content,
            "user_followers": tweet.user.followersCount,
            "user_verified": tweet.user.verified
        })
    return pd.DataFrame(tweets_list)

爬取后保存为CSV,避免重复爬取浪费资源。

2. 情感分析模块

优先用金融领域专用的情感模型(比如FinBERT),比通用模型(VADER)更适配财经文本:

from transformers import pipeline

# 加载FinBERT情感分析管道
sentiment_analyzer = pipeline("sentiment-analysis", model="yiyanghkust/finbert-tone")

def get_sentiment_score(text):
    result = sentiment_analyzer(text)[0]
    # 转换为-1到1的连续得分:Negative=-1, Neutral=0, Positive=1
    score_map = {"Negative": -1, "Neutral": 0, "Positive": 1}
    return score_map[result["label"]] * result["score"]

对每条推特计算情感得分后,添加到之前的DataFrame中。

3. 特征工程模块

按日期聚合情感特征,同时加入金融市场数据(比如EURUSD的日K线数据):

def aggregate_daily_features(tweets_df, forex_df):
    # 按日期聚合情感特征
    daily_sentiment = tweets_df.groupby("date").agg(
        avg_sentiment=("sentiment_score", "mean"),
        sentiment_std=("sentiment_score", "std"),
        positive_ratio=("sentiment_score", lambda x: sum(x > 0)/len(x)),
        # 高影响力用户(粉丝>10万或认证)的情感均值
        verified_avg_sentiment=("sentiment_score", lambda x: x[tweets_df["user_verified"] | (tweets_df["user_followers"] > 100000)].mean())
    ).reset_index()
    
    # 合并金融数据(forex_df需包含date, close, open, high, low, volume字段)
    combined_df = pd.merge(daily_sentiment, forex_df, on="date", how="inner")
    
    # 生成标签:次日收盘价相对于当日收盘价的涨跌(涨=1,跌=0)
    combined_df["next_day_return"] = combined_df["close"].shift(-1) - combined_df["close"]
    combined_df["label"] = (combined_df["next_day_return"] > 0).astype(int)
    
    # 移除最后一行(无次日数据)和缺失值
    combined_df = combined_df.dropna().iloc[:-1]
    return combined_df

4. 模型训练与评估模块

按时间顺序划分数据集(禁止随机划分,避免数据泄露),用XGBoost或逻辑回归先做基准测试:

from xgboost import XGBClassifier
from sklearn.metrics import accuracy_score, f1_score

def train_model(features_df):
    # 特征列:情感特征+金融特征
    feature_cols = ["avg_sentiment", "sentiment_std", "positive_ratio", "verified_avg_sentiment", "open", "high", "low", "volume"]
    X = features_df[feature_cols]
    y = features_df["label"]
    
    # 按时间划分训练集和测试集(前80%训练,后20%测试)
    split_idx = int(len(X) * 0.8)
    X_train, X_test = X.iloc[:split_idx], X.iloc[split_idx:]
    y_train, y_test = y.iloc[:split_idx], y.iloc[split_idx:]
    
    # 训练模型
    model = XGBClassifier(random_state=42)
    model.fit(X_train, y_train)
    
    # 评估
    y_pred = model.predict(X_test)
    print(f"测试集准确率: {accuracy_score(y_test, y_pred):.2f}")
    print(f"测试集F1-score: {f1_score(y_test, y_pred):.2f}")
    return model

5. 迭代优化模块

  • 尝试加入更多宏观特征:比如美联储利率决议、欧元区CPI数据等,这些对EURUSD涨跌的影响远大于推特情感
  • 调整情感加权规则:比如按用户的推文互动量(点赞、转发数)加权,而非仅粉丝数
  • 尝试时序模型:比如LSTM,利用多日的情感和金融数据序列做预测

实战提醒

  • 推特数据时效性很强,爬取时要确保覆盖目标日期的所有相关内容,避免遗漏关键事件(比如央行讲话当天的推文)
  • 情感分析的准确率是基础,如果模型效果差,先排查情感得分是否符合金融语境,比如“ECB hikes rates”这类新闻,FinBERT会判断为负面(利空欧元),而通用模型可能误判为中性
  • 不要过度依赖推特情感,它只是辅助特征,核心还是金融市场本身的量价和宏观数据

内容的提问来源于stack exchange,提问作者Chigstardan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 23:27:18