feat: add prediction and omit empty Buy/Sell

This commit is contained in:
ytshih committed 2026-09-07 09:04:34 +08:00
1 parent 521588f992
commit ba63c5deb0
5 files changed
+99 -54

No files matched your search

+31 -14
View File
@@ -18,7 +18,7 @@ You will be given today's prices (with percent change) and recent news headlines
Structure your response in Markdown, formatted for Discord (short lines, ` + "`**bold**`" + ` section headers, no HTML, no huge tables). Use exactly these section headers, in exactly this order, every single time — do not rename, reorder, merge, or skip a section (write "nothing notable" under a section rather than omitting it):
1. **Summary** — one paragraph, market-wide.
1. **Summary** — one paragraph, market-wide, ending with an overall near-term directional call (e.g. risk-on, risk-off, mixed/range-bound).
2. **Crypto** — brief commentary per asset grounded in the given price/news data.
3. **NASDAQ Equities** — same, grouped sensibly (e.g. by sector) if useful.
4. **Futures** — gold, silver, crude oil.
@@ -27,14 +27,19 @@ Structure your response in Markdown, formatted for Discord (short lines, ` + "`*
Keep the whole message under roughly 1500 words. Ground every claim in the provided data — do not fabricate news or prices. If data for an asset is missing, say so briefly rather than inventing a view. End with a one-line disclaimer that this is not financial advice.
## Deduplicating against the previous briefing
## Predictions
If the user turn includes a section titled "Previous Briefing", that was posted about 5 hours ago to the same channel — treat it as what the reader already knows, not as data to re-derive conclusions from. Since reports repeat several times a day:
- Do not re-explain news items, price moves, or commentary that already appeared there and have not materially changed since. It is fine, and expected, for a section to be much shorter than before when nothing new happened — say so in one short line (e.g. "Crypto: no material change since last briefing.") rather than restating the same analysis in new words.
- Always still report today's current price and percent change for every asset — that number itself is never a repeat, only the commentary around it can be.
Within each of the Crypto / NASDAQ Equities / Futures / Forex sections, end the commentary for each asset (or the section as a whole, if grouped) with a short, explicit near-term prediction — direction (up / down / sideways) over the next few hours to the next day or two, plus a one-sentence rationale that ties directly back to the price action and news you were given. Hedge honestly: if the data doesn't support a confident call, say so ("no clear signal either way") rather than inventing conviction. Never predict beyond what the given prices and headlines can support — no macro speculation not grounded in the provided news.
## Deduplicating against previous briefings
If the user turn includes a section titled "Previous Briefings", it contains up to the last 5 runs posted to this same channel (each roughly 5 hours apart, oldest first), treat all of them together as what the reader already knows, not as data to re-derive conclusions from. Since reports repeat several times a day:
- Do not re-explain news items, price moves, commentary, or predictions that already appeared in any of those briefings and have not materially changed since. It is fine, and expected, for a section to be much shorter than before when nothing new happened — say so in one short line (e.g. "Crypto: no material change since last briefing.") rather than restating the same analysis in new words.
- Always still report today's current price and percent change for every asset, and still give a current prediction — those are never repeats, only the surrounding commentary can be.
- Treat the 5 briefings as a rolling history: if something has been true and unchanged across several of them, say how long it's persisted (e.g. "still range-bound since ~15h ago") instead of re-describing it each time.
- Only carry forward previously-mentioned info if it remains genuinely important and ongoing (e.g. a new regulation, a major macro event, an unresolved earnings surprise) — mention it briefly as a reminder ("still in effect: ...") rather than re-explaining it in full.
- If nothing previously flagged in Watch has resolved or changed, say so briefly instead of repeating the full original description.
- If there is no Previous Briefing section (first-ever run), write the full briefing normally.
- If there is no Previous Briefings section (first-ever run), write the full briefing normally.
After the full briefing above, on its own line, output exactly:
===RECOMMENDATIONS_JSON===
@@ -42,19 +47,31 @@ followed immediately by a single JSON object (no markdown code fence, no comment
{"recommendations": [{"symbol": "AAPL", "action": "buy", "reason": "one short sentence"}]}
"action" must be exactly "buy" or "sell". Only include symbols from the watchlist you have an actual buy or sell call on — omit any you'd rate hold/neutral. It is fine for this list to be empty ({"recommendations": []}) if nothing warrants a call. This JSON must be the very last thing in your response.`
// PreviousBriefing is one prior run's archived report, used so
// BuildUserPrompt can give Claude a rolling window of recent briefings to
// dedup against (see archive.LoadRecent).
type PreviousBriefing struct {
When time.Time
Text string
}
// BuildUserPrompt renders the fetched result into the user-turn text sent
// alongside SystemPrompt. previousReport is the narrative text of the last
// archived briefing (see archive.LoadLatest), used so Claude can dedup this
// briefing against it; pass "" if none exists yet (e.g. first-ever run).
func BuildUserPrompt(targets config.Targets, result fetch.Result, previousReport string) string {
// alongside SystemPrompt. previous holds up to the last few archived
// briefings (oldest first, see archive.LoadRecent), used so Claude can dedup
// this briefing against that rolling history; pass nil if none exist yet
// (e.g. first-ever run).
func BuildUserPrompt(targets config.Targets, result fetch.Result, previous []PreviousBriefing) string {
var b strings.Builder
fmt.Fprintf(&b, "Date: %s\n\n", time.Now().Format("2006-01-02"))
if previousReport != "" {
b.WriteString("## Previous Briefing (posted ~5 hours ago — see system prompt for how to use this)\n\n")
b.WriteString(previousReport)
b.WriteString("\n\n")
if len(previous) > 0 {
fmt.Fprintf(&b, "## Previous Briefings (last %d run(s), oldest first — see system prompt for how to use this)\n\n", len(previous))
for _, p := range previous {
fmt.Fprintf(&b, "### Briefing from %s (~%s ago)\n\n", p.When.Format("2006-01-02 15:04 MST"), time.Since(p.When).Round(time.Minute))
b.WriteString(p.Text)
b.WriteString("\n\n")
}
}
b.WriteString("## Prices\n\n")