社交媒体发布
Richfolio 可以选择性地把买入信号发布到公开的社交账号 — X/Twitter、Facebook 主页、Threads 账号和 LinkedIn 主页 — 与邮件 + Telegram 简报一同发出。它只在每日和盘中模式下运行(绝不在每周或刷新模式下运行)。
这是完全可选的。如果你没有设置任何社交凭据,就什么都不会发布,Richfolio 的其余功能与之前完全一致 — 每个平台会记录一行 “credentials not set — skipping” 并继续运行。
会发布什么内容
发布内容刻意保持通用,以确保不泄露任何隐私:
- 仅发布 STRONG BUY 和 BUY 信号(HOLD/WAIT 会被跳过)。
- 每条信号显示股票代码、操作、置信度、一段简短理由,以及可选的价值评级 — 别无其它。
- 目标投资组合和观察清单的标的统一合并为”信号” — 没有”组合 vs 观察清单”的标签,因此绝不会暴露你的持仓。
- 绝不发布: 配置比例、缺口、建议买入金额、股数、投资组合总值。
src/socialContent.ts中的buildSignalLines()是唯一的白名单收口处,sanitizeReason()会剥离 AI 可能写进理由里的任何配置缺口、美元金额或重叠折扣文本。两者都有单元测试覆盖。 - 股票代码在 Facebook / Threads / LinkedIn 上渲染为可点击的
#hashtag(cashtag 仅在 X 上生效,在那里它保持为$cashtag)。在非 X 平台上还会追加一组可配置的通用 hashtag 以扩大触达。 - 每条发布内容都以免责声明结尾:“Not financial advice. Auto-generated by Richfolio.”(非投资建议,由 Richfolio 自动生成。)
启用 / 禁用
config.json 中的 social 块是总开关(下方为默认值):
"social": {
"enabled": true,
"includeLinkInX": false,
"hashtags": ["investing", "stocks", "stockmarket", "ETFs"]
}
enabled: false— 无论凭据是否设置,都禁用所有社交发布。includeLinkInX— 在 X 发布中包含分析链接。默认关闭,因为带链接会抬高 X 的按次计费成本。hashtags— 在 Facebook / Threads / LinkedIn 上追加的通用 hashtag(开头的#可省略)。不会加到 X 上。
每个平台还会额外根据其自身凭据来把关,所以即使 enabled 为 true,没有密钥的平台仍会被跳过。
Secret 汇总
将这些添加为仓库 Secret(Settings → Secrets and variables → Actions → Secrets)。全都是可选的 — 只设置你想要的平台。
| Secret | 平台 | 说明 |
|---|---|---|
FACEBOOK_PAGE_ID | 你主页的数字 id | |
FACEBOOK_PAGE_TOKEN | 长效主页访问令牌 | |
THREADS_USER_ID | Threads | 你的 Threads 数字用户 id |
THREADS_ACCESS_TOKEN | Threads | 长效令牌(约 60 天过期) |
THREADS_TOKEN_PAT | Threads | 可选 PAT,用于自动刷新 Threads 令牌(见下文) |
LINKEDIN_ACCESS_TOKEN | 带 w_organization_social 的 OAuth 2.0 令牌 | |
LINKEDIN_ORG_URN | 例如 urn:li:organization:123456 | |
X_API_KEY / X_API_SECRET | X/Twitter | OAuth 1.0a consumer 密钥 |
X_ACCESS_TOKEN / X_ACCESS_TOKEN_SECRET | X/Twitter | OAuth 1.0a 用户令牌 |
Facebook 主页设置
运行时只需要两个值:FACEBOOK_PAGE_ID 和一个长效的 FACEBOOK_PAGE_TOKEN。因为你是以自己主页管理员的身份发布到自己的主页,所以可以一直停留在应用的开发模式(Development mode) — 无需应用审核(App Review)。
1. 创建一个 Meta 应用
- 进入 developers.facebook.com → My Apps → Create App。
- 选择 Other → Business 应用类型并命名(例如 “Richfolio Poster”)。
2. 添加主页管理用例
- 在应用中打开 Use cases → 选择 Manage everything on your Page。
- 打开其 Permissions 并 Add(标准访问权限即可 — 忽略 “Get Advanced Access”):
pages_manage_posts— 发布到信息流(最关键的一项)pages_read_engagementpages_show_list
它们应显示为 “Ready for testing” — 意味着现在已可供你以管理员身份使用。
3. 获取用户令牌
- 打开 Graph API Explorer。
- 选择你的应用 → Get User Access Token → 勾选三项
pages_*权限 → Generate Access Token → 批准。
4. 生成长效主页令牌
Richfolio 自带一个帮你完成令牌交换的辅助脚本。临时添加到 .env:
FACEBOOK_PAGE_ID=your_page_id # numeric Page id
FACEBOOK_APP_SECRET=... # App settings → Basic → App secret
FB_USER_TOKEN=... # the user token from step 3
然后运行:
npx tsx smoke/fb-page-token.ts
它会把短效用户令牌交换为长效令牌,找到你的主页,并打印一个永不过期的主页令牌。把它粘贴到 FACEBOOK_PAGE_TOKEN,然后从 .env 中删除 FACEBOOK_APP_SECRET 和 FB_USER_TOKEN — 它们仅用于设置阶段,运行时绝不会用到。
5. 验证
npx tsx smoke/smoke-facebook.ts # checks the token (no posting)
npx tsx smoke/smoke-facebook.ts --post --cleanup # posts a test, then deletes it
出现 PASS 即确认该令牌是有效的主页令牌,且端到端发布正常工作。
6. 添加到 GitHub
将 FACEBOOK_PAGE_ID 和 FACEBOOK_PAGE_TOKEN 添加为仓库 Secret。不要添加 app secret 或用户令牌。
令牌有效期: 主页令牌实际上是永久的,但如果你更改 Facebook 密码、撤销该应用,或不再是主页管理员,它就会失效。如果发布停止,从第 3 步重新生成。
Threads 设置
Threads 复用与 Facebook相同的 Meta 应用。你需要一个 THREADS_USER_ID 和一个长效的 THREADS_ACCESS_TOKEN。你授权的那个账号就是发布内容所来自的账号 — 请使用你的品牌 Threads 账号,且该账号必须为公开。
1. 为 Meta 应用添加 Threads 用例:Use cases → Access the Threads API。启用 threads_basic 和 threads_content_publish 范围。
2. 把自己加为 Threads 测试者:App Dashboard → App roles → Roles → Add People → Threads Tester → 输入你的 Threads 用户名 → 在 Threads 应用中接受邀请(Settings → Account → Website permissions)。
3. 生成长效令牌:在 Threads 用例的 Settings 中,User Token Generator 会列出你的测试者账号 → Generate token。它本身就是长效的 — 无需交换。把它粘贴到 .env 的 THREADS_ACCESS_TOKEN。
4. 发现你的用户 id 并验证:
npx tsx smoke/smoke-threads.ts # prints THREADS_USER_ID; set it in .env
npx tsx smoke/smoke-threads.ts --post --cleanup # posts a test (delete may be manual)
5. 将 THREADS_USER_ID 和 THREADS_ACCESS_TOKEN 添加到 GitHub Secret。
令牌过期与自动刷新: Threads 长效令牌约 60 天过期。工作流
.github/workflows/refresh-threads-token.yml会每月刷新令牌并写回 secret — 前提是你还添加了一个THREADS_TOKEN_PATsecret(一个具有仓库 Secrets: Read and write 的 fine-grained PAT)。没有该 PAT 的话,请在令牌过期前手动刷新。
LinkedIn 主页设置
LinkedIn 是免费的,但把关最严。你需要:
- 一个与你的公司主页关联的 LinkedIn 开发者应用(Developer app)。
- “Community Management API” 产品,它授予
w_organization_social范围。申请它需要你的应用的公司关联已验证(Settings 标签页),并提交一份访问申请表(其中会要求填写已注册的公司名称)。 - 一个带
w_organization_social的 OAuth 2.0 访问令牌,由主页管理员生成。
设置:
LINKEDIN_ACCESS_TOKEN— OAuth 2.0 令牌。LINKEDIN_ORG_URN— 你的组织 URN,例如urn:li:organization:123456(数字在你的公司主页 URL 中)。LINKEDIN_API_VERSION— 可选覆盖项(默认为某个较新的YYYYMM)。
用 npx tsx smoke/smoke-linkedin.ts(令牌检查)和 --post --cleanup(发布测试)进行验证。
LinkedIn 访问令牌约 60 天过期(刷新令牌约 365 天)。请计划定期刷新。向组织发布需要一个已注册的企业;如果你没有,可以改造发布器,通过自助的 “Share on LinkedIn” 产品(
w_member_social)从个人资料发布。
X / Twitter 设置
自 2026 年 2 月起,X 不再有免费发布层级。 发布按次计费(约每条 $0.015,带链接则更贵)。Richfolio 自带 X 发布器,但在你添加密钥之前它会保持休眠。
发布使用 OAuth 1.0a 用户上下文。在 X Developer Portal 中创建一个具有 Read and Write 权限的项目/应用,并生成:
X_API_KEY/X_API_SECRET— consumer(API)密钥与密文。X_ACCESS_TOKEN/X_ACCESS_TOKEN_SECRET— 你账号的访问令牌与密文。
在 config.json 中保持 includeLinkInX 关闭,以降低每条发布的成本。
它如何运行
在每日和盘中模式下,邮件和 Telegram 发送之后,Richfolio 会调用 sendSocialPosts()(src/social.ts)。每个平台都在各自的 try/catch 内发布,因此某个平台失败绝不会阻塞其它平台 — 也不会影响已经发出的邮件/Telegram。
如果你 fork 了 Richfolio,社交发布会保持关闭,直到你用自己的账号完成上述设置 — 凭据无法共享,因为每个令牌都发布到其所有者的账号。