Add S&P 500 drawdown-from-ATH alert and ATH status in close alert#20
Merged
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
This PR adds a new S&P 500 (SPY) drawdown-from-all-time-high (ATH) threshold alert to the alerts worker, and enriches the existing daily SPY close alert with ATH context so recipients can see whether the latest close is a new ATH or how far below the ATH it is.
Changes:
- Introduces a new scheduled
sp500-drawdownalert that detects stateless crossings of configurable drawdown thresholds (10/20/30/40/50%) from ATH. - Extends the daily
sp500-closealert to fetch full history and include ATH / drawdown-from-ATH details. - Registers the new alert in the alerts registry and adds unit tests for the drawdown alert behavior.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| apps/alerts/src/alerts/sp500-drawdown.ts | New alert that detects drawdown band crossings vs ATH and emits Telegram HTML messages. |
| apps/alerts/src/alerts/sp500-drawdown.test.ts | Unit tests covering drawdown band crossing detection and messaging behavior. |
| apps/alerts/src/alerts/sp500-close.ts | Enriches the daily close alert with ATH / drawdown context and switches to full history fetch. |
| apps/alerts/src/alerts/index.ts | Registers the new drawdown alert in the alert registry. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+16
to
+24
| const bandFor = (drawdown: number): number => { | ||
| let band = 0; | ||
| for (const threshold of DRAWDOWN_THRESHOLDS) { | ||
| if (drawdown >= threshold) { | ||
| band = threshold; | ||
| } | ||
| } | ||
| return band; | ||
| }; |
Comment on lines
+25
to
+37
| // The bar with the highest close; `latest` is at the ATH when it ties it. | ||
| const athBar = series.bars.reduce((max: DailyBar, bar: DailyBar) => | ||
| bar.close > max.close ? bar : max | ||
| ); | ||
| const isNewAth = latest.close >= athBar.close; | ||
|
|
||
| const head = `📈 SPY close ${latest.date}: $${latest.close.toFixed(2)}`; | ||
| if (isNewAth) { | ||
| return `${head} — 🚀 all-time high`; | ||
| } | ||
|
|
||
| const drawdown = (athBar.close - latest.close) / athBar.close; | ||
| return `${head} (−${(drawdown * 100).toFixed(1)}% from ATH $${athBar.close.toFixed(2)} on ${athBar.date})`; |
Comment on lines
+15
to
+18
| // `full` history is required to establish a real all-time high. | ||
| const series = await client.getDailyTimeSeries("SPY", { | ||
| outputSize: "full", | ||
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
DRAWDOWN_THRESHOLDSarray.0 8 * * *cron — no wrangler or env changes.How to test
pnpm --filter @repo/alerts test
pnpm typecheck
pnpm lint
pnpm format:check
Security review
No security-impacting changes.