Merge pull request #10 from Aitous/iterate/current
learn(iterate): automated improvements — 2026-04-12
This commit is contained in:
commit
50889fd667
|
|
@ -110,7 +110,7 @@ Run `git commit` with a message in the format: `learn(iterate): YYYY-MM-DD — <
|
|||
|
||||
Then check for an existing open PR on branch `iterate/current`:
|
||||
```bash
|
||||
EXISTING=$(gh pr list --head iterate/current --state open --json number --jq '.[0].number // empty')
|
||||
EXISTING=$(gh pr list --repo Aitous/TradingAgents --head iterate/current --state open --json number --jq '.[0].number // empty')
|
||||
```
|
||||
|
||||
If one exists: push to that branch and update the PR description with your findings appended.
|
||||
|
|
@ -119,6 +119,7 @@ If none exists: create branch `iterate/current`, push, open PR against `main`:
|
|||
git checkout -b iterate/current
|
||||
git push -u origin iterate/current
|
||||
gh pr create \
|
||||
--repo Aitous/TradingAgents \
|
||||
--title "learn(iterate): automated improvements — $(date +%Y-%m-%d)" \
|
||||
--body "$(cat docs/iterations/LEARNINGS.md)" \
|
||||
--label "automated,iteration" \
|
||||
|
|
|
|||
|
|
@ -160,13 +160,13 @@ Run `git commit` with a message in the format:
|
|||
|
||||
Then check for an existing open PR on branch `research/current`:
|
||||
```bash
|
||||
EXISTING=$(gh pr list --head research/current --state open --json number --jq '.[0].number // empty')
|
||||
EXISTING=$(gh pr list --repo Aitous/TradingAgents --head research/current --state open --json number --jq '.[0].number // empty')
|
||||
```
|
||||
|
||||
If one exists:
|
||||
```bash
|
||||
git push origin HEAD:research/current
|
||||
gh pr edit "$EXISTING" \
|
||||
gh pr edit "$EXISTING" --repo Aitous/TradingAgents \
|
||||
--body "$(cat docs/iterations/LEARNINGS.md | head -30)"
|
||||
```
|
||||
|
||||
|
|
@ -175,6 +175,7 @@ If none exists:
|
|||
git checkout -b research/current
|
||||
git push -u origin research/current
|
||||
gh pr create \
|
||||
--repo Aitous/TradingAgents \
|
||||
--title "research: new strategy findings — $(date +%Y-%m-%d)" \
|
||||
--body "$(cat docs/iterations/LEARNINGS.md | head -30)" \
|
||||
--label "automated,research" \
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@ jobs:
|
|||
SEPARATOR="---"
|
||||
|
||||
EXISTING_PR=$(gh pr list \
|
||||
--repo Aitous/TradingAgents \
|
||||
--head "$BRANCH" \
|
||||
--state open \
|
||||
--json number \
|
||||
|
|
@ -96,7 +97,7 @@ jobs:
|
|||
echo "$SEPARATOR"
|
||||
echo "*Last updated: ${DATE} by automated iterate workflow*"
|
||||
} > /tmp/pr_body.md
|
||||
gh pr edit "$EXISTING_PR" --body-file /tmp/pr_body.md
|
||||
gh pr edit "$EXISTING_PR" --repo Aitous/TradingAgents --body-file /tmp/pr_body.md
|
||||
echo "Updated existing PR #${EXISTING_PR}"
|
||||
else
|
||||
git checkout -b "$BRANCH" 2>/dev/null || git checkout "$BRANCH"
|
||||
|
|
@ -108,9 +109,10 @@ jobs:
|
|||
echo "*Opened: ${DATE} by automated iterate workflow*"
|
||||
echo "*Merge to apply learnings and reset the iteration cycle.*"
|
||||
} > /tmp/pr_body.md
|
||||
gh label create "automated" --color "0075ca" --description "Automated workflow" 2>/dev/null || true
|
||||
gh label create "iteration" --color "e4e669" --description "Iteration system" 2>/dev/null || true
|
||||
gh label create "automated" --color "0075ca" --description "Automated workflow" --repo Aitous/TradingAgents 2>/dev/null || true
|
||||
gh label create "iteration" --color "e4e669" --description "Iteration system" --repo Aitous/TradingAgents 2>/dev/null || true
|
||||
gh pr create \
|
||||
--repo Aitous/TradingAgents \
|
||||
--title "learn(iterate): automated improvements — ${DATE}" \
|
||||
--body-file /tmp/pr_body.md \
|
||||
--label "automated,iteration" \
|
||||
|
|
|
|||
|
|
@ -89,6 +89,7 @@ jobs:
|
|||
SEPARATOR="---"
|
||||
|
||||
EXISTING_PR=$(gh pr list \
|
||||
--repo Aitous/TradingAgents \
|
||||
--head "$BRANCH" \
|
||||
--state open \
|
||||
--json number \
|
||||
|
|
@ -103,7 +104,7 @@ jobs:
|
|||
echo "$SEPARATOR"
|
||||
echo "*Last updated: ${DATE} by automated research-strategy workflow*"
|
||||
} > /tmp/pr_body.md
|
||||
gh pr edit "$EXISTING_PR" --body-file /tmp/pr_body.md
|
||||
gh pr edit "$EXISTING_PR" --repo Aitous/TradingAgents --body-file /tmp/pr_body.md
|
||||
echo "Updated existing PR #${EXISTING_PR}"
|
||||
else
|
||||
git checkout -b "$BRANCH" 2>/dev/null || git checkout "$BRANCH"
|
||||
|
|
@ -115,9 +116,10 @@ jobs:
|
|||
echo "*Opened: ${DATE} by automated research-strategy workflow*"
|
||||
echo "*Merge to apply research findings and reset the research cycle.*"
|
||||
} > /tmp/pr_body.md
|
||||
gh label create "automated" --color "0075ca" --description "Automated workflow" 2>/dev/null || true
|
||||
gh label create "research" --color "d93f0b" --description "Research findings" 2>/dev/null || true
|
||||
gh label create "automated" --color "0075ca" --description "Automated workflow" --repo Aitous/TradingAgents 2>/dev/null || true
|
||||
gh label create "research" --color "d93f0b" --description "Research findings" --repo Aitous/TradingAgents 2>/dev/null || true
|
||||
gh pr create \
|
||||
--repo Aitous/TradingAgents \
|
||||
--title "research: new strategy findings — ${DATE}" \
|
||||
--body-file /tmp/pr_body.md \
|
||||
--label "automated,research" \
|
||||
|
|
|
|||
|
|
@ -2,13 +2,26 @@
|
|||
|
||||
## Current Understanding
|
||||
Scans r/investing, r/stocks, r/wallstreetbets for DD posts. LLM quality score is
|
||||
computed but not used for filtering — using it (80+ = HIGH, 60-79 = MEDIUM, <60 = skip)
|
||||
would reduce noise. Subreddit weighting matters: r/investing posts are more reliable
|
||||
than r/pennystocks. Post title and LLM score should appear in candidate context.
|
||||
computed and used for filtering — posts scoring >=80 are HIGH priority, 60-79 are
|
||||
MEDIUM, and <60 are skipped. This quality filter is the key differentiator from
|
||||
the reddit_trending scanner.
|
||||
|
||||
The quality_score filter (>=60) is working: social_dd is the ONLY strategy with
|
||||
positive 30d returns (+0.94% avg) and 55% 30d win rate across all tracked strategies.
|
||||
This is confirmed by P&L data spanning 608 total recommendations.
|
||||
|
||||
## Evidence Log
|
||||
_(populated by /iterate runs)_
|
||||
|
||||
### 2026-04-11 — P&L review
|
||||
- 26 recommendations. 30d avg return: +0.94% (only positive 30d avg among all strategies).
|
||||
- 30d win rate: 55%. 7d win rate: 44%. 1d win rate: 46.2%.
|
||||
- The positive 30d return despite negative 1d/7d averages suggests DD-based picks
|
||||
need time to play out — the thesis takes weeks, not days, to materialize.
|
||||
- Compare with social_hype (reddit_trending, no quality filter): -10.64% 30d avg.
|
||||
The quality_score filter alone appears to be the separator between signal and noise.
|
||||
- The code already implements the quality filter correctly (>=60 threshold).
|
||||
- Confidence: high (26 data points, consistent pattern vs. sister scanner)
|
||||
|
||||
## Pending Hypotheses
|
||||
- [ ] Does filtering by LLM quality score >60 meaningfully reduce false positives?
|
||||
- [ ] Does subreddit weighting change hit rates?
|
||||
- [ ] Does filtering by LLM quality score >80 (HIGH only) further improve outcomes vs >60?
|
||||
- [ ] Does subreddit weighting change hit rates (r/investing vs r/wallstreetbets)?
|
||||
|
|
|
|||
|
|
@ -5,8 +5,25 @@ Tracks mention velocity across subreddits. 50+ mentions in 6 hours = HIGH priori
|
|||
20-49 = MEDIUM. Mention count should appear in context ("47 mentions in 6hrs").
|
||||
Signal is early-indicator oriented — catches momentum before price moves.
|
||||
|
||||
P&L data shows this is among the worst-performing strategies: -10.64% avg 30d return,
|
||||
13.6% 1d win rate. The root cause is that LOW and MEDIUM priority candidates (any
|
||||
ticker with 1-49 raw mentions) add noise without signal. Only HIGH priority (>=50
|
||||
mentions) candidates have a plausible momentum thesis. Scanner now skips LOW and
|
||||
MEDIUM priority candidates.
|
||||
|
||||
## Evidence Log
|
||||
_(populated by /iterate runs)_
|
||||
|
||||
### 2026-04-11 — P&L review
|
||||
- 22 recommendations, 1d win rate 13.6%, 7d win rate 16.7%, 30d win rate 15.4%.
|
||||
- Avg 30d return: -10.64%. Second worst strategy after news_catalyst (-17.5%).
|
||||
- Contrast with social_dd (+0.94% 30d): the absence of a quality filter is the
|
||||
key differentiator. reddit_trending emits any ticker with raw text mentions.
|
||||
- The raw text mention count (computed via `result.upper().count(ticker)`) is
|
||||
susceptible to false matches (short tickers appear in unrelated words).
|
||||
- Primary fix: skip MEDIUM and LOW priority candidates — only emit tickers with
|
||||
>=50 mentions. This restricts output to genuinely viral tickers.
|
||||
- Confidence: high (clear signal from 22 recs all losing, vs. DD scanner positive)
|
||||
|
||||
## Pending Hypotheses
|
||||
- [ ] Does mention velocity (rate of increase) outperform raw mention count?
|
||||
- [ ] Do HIGH priority (>=50 mention) picks specifically outperform MEDIUM (20-49)?
|
||||
|
|
|
|||
|
|
@ -1,14 +1,36 @@
|
|||
# Semantic News Scanner
|
||||
|
||||
## Current Understanding
|
||||
Currently regex-based extraction, not semantic. Headline text is not included in
|
||||
candidate context — the context just says "Mentioned in recent market news" which
|
||||
is not informative. Catalyst classification from headline keywords (upgrade/FDA/
|
||||
acquisition/earnings) would improve LLM scoring quality significantly.
|
||||
Currently regex-based extraction, not semantic. Headline text IS included in
|
||||
candidate context via `news_headline` field (improved from prior version).
|
||||
Catalyst classification from headline keywords maps to priority:
|
||||
- CRITICAL: FDA approval, acquisition, merger, breakthrough
|
||||
- HIGH: upgrade, beat, contract win, patent, guidance raise
|
||||
- MEDIUM: downgrade, miss, lawsuit, investigation, recall, warning
|
||||
|
||||
P&L data shows `news_catalyst` is the worst-performing strategy: -17.5% avg 30d
|
||||
return, 0% 7d win rate, 12.5% 1d win rate. Root cause: MEDIUM-priority candidates
|
||||
(negative catalysts — downgrades, lawsuits, recalls) are included in the candidate
|
||||
pool and frequently get through to recommendations with a bullish framing. Scanner
|
||||
now restricted to CRITICAL-only to eliminate negative-catalyst contamination.
|
||||
|
||||
## Evidence Log
|
||||
_(populated by /iterate runs)_
|
||||
|
||||
### 2026-04-11 — P&L review
|
||||
- 8 recommendations, 1d win rate 12.5%, 7d win rate 0% (worst of all strategies).
|
||||
- Avg 30d return: -17.5%. Avg 1d return: -4.19%. Avg 7d return: -8.79%.
|
||||
- Sample shows WTI (W&T Offshore) appearing twice (Apr 3 and Apr 6) as news_catalyst
|
||||
based on geopolitical oil price spike — both marked as "high" risk. The spike
|
||||
reversed, consistent with the -17.5% 30d outcome.
|
||||
- Root issue 1: MEDIUM-priority keywords include negative events (downgrade, miss,
|
||||
lawsuit) that generate candidates with inherently negative thesis.
|
||||
- Root issue 2: CRITICAL/HIGH keywords like "upgrade" and "patent" overlap with
|
||||
noise in global news feeds that mention these terms incidentally.
|
||||
- Fix applied: only emit candidates when headline matches CRITICAL-priority keywords.
|
||||
Eliminates the negative-catalyst false positives.
|
||||
- Confidence: medium (8 data points; market downturn may amplify losses)
|
||||
|
||||
## Pending Hypotheses
|
||||
- [ ] Would embedding-based semantic matching outperform keyword regex?
|
||||
- [ ] Does catalyst classification (FDA vs earnings vs acquisition) affect hit rate?
|
||||
- [ ] Do CRITICAL-only candidates (post-fix) outperform CRITICAL+HIGH baseline?
|
||||
|
|
|
|||
|
|
@ -19,7 +19,10 @@ class InsiderBuyingScanner(BaseScanner):
|
|||
def __init__(self, config: Dict[str, Any]):
|
||||
super().__init__(config)
|
||||
self.lookback_days = self.scanner_config.get("lookback_days", 7)
|
||||
self.min_transaction_value = self.scanner_config.get("min_transaction_value", 25000)
|
||||
# Raised from $25K to $100K: P&L data (178 recs, -2.05% 30d avg) suggests
|
||||
# sub-$100K transactions add noise. Tests the insider_buying-min-txn-100k
|
||||
# hypothesis registered 2026-04-07.
|
||||
self.min_transaction_value = self.scanner_config.get("min_transaction_value", 100_000)
|
||||
|
||||
def scan(self, state: Dict[str, Any]) -> List[Dict[str, Any]]:
|
||||
if not self.is_enabled():
|
||||
|
|
|
|||
|
|
@ -65,10 +65,13 @@ class RedditTrendingScanner(BaseScanner):
|
|||
|
||||
if count >= 50:
|
||||
priority = Priority.HIGH.value
|
||||
elif count >= 20:
|
||||
priority = Priority.MEDIUM.value
|
||||
else:
|
||||
priority = Priority.LOW.value
|
||||
# Skip MEDIUM (20-49) and LOW (<20) priority candidates.
|
||||
# P&L data showed social_hype at -10.64% avg 30d return across
|
||||
# 22 recommendations — low-count mentions are noise, not signal.
|
||||
# Only genuinely viral tickers (>=50 mentions) have a plausible
|
||||
# momentum thesis worth surfacing.
|
||||
continue
|
||||
|
||||
context = f"Trending on Reddit: ~{count} mentions"
|
||||
|
||||
|
|
|
|||
|
|
@ -130,9 +130,14 @@ class SemanticNewsScanner(BaseScanner):
|
|||
for ticker, headline in list(ticker_headlines.items())[: self.limit]:
|
||||
priority = self._classify_catalyst(headline)
|
||||
|
||||
context = (
|
||||
f"News catalyst: {headline}" if headline else "Mentioned in recent market news"
|
||||
)
|
||||
# Only emit candidates with CRITICAL catalysts (FDA approval,
|
||||
# acquisition, merger, etc.). HIGH and MEDIUM candidates include
|
||||
# negative events (downgrades, lawsuits) that produce false positives
|
||||
# and dragged news_catalyst to -17.5% avg 30d return (0% 7d win rate).
|
||||
if priority != Priority.CRITICAL.value:
|
||||
continue
|
||||
|
||||
context = f"News catalyst: {headline}"
|
||||
|
||||
candidates.append(
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue