feat: Pattern Explorer — taxonomy tree + 23 historical patterns + instrument lens
- PatternExplorer.tsx: new page with two views:
• Tree View — 6-root taxonomy (geopolitical, monetary_policy, economic,
commodity, risk_off, market_structure) with collapsible sub-nodes;
pattern cards appear on node selection
• Instrument Lens — search any ticker (e.g. GLD, FXE) to see every
pattern + scenario that references it, with matching trades highlighted
- geo_analyzer.py: PATTERN_TAXONOMY tree constant + taxonomy_path on all
patterns; 15 new documented patterns P009-P023 (BoJ YCC, SVB crisis,
Taiwan semis, OPEC cuts, Fed pivot, Debt ceiling, Iran nuclear, DPRK,
VIX backwardation, ECB surprise, Extreme Fear contrarian, S. China Sea,
European energy, CPI hot print, Flash crash)
- patterns.py: GET /api/patterns/taxonomy, GET /api/patterns/by-instrument
- database.py: taxonomy_path migration + seed_builtin_patterns updates path
- App.tsx: /patterns → PatternExplorer, /patterns/edit → PatternEditor
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -81,6 +81,8 @@ def init_db():
|
||||
# Convergence Phase 1 — thematic classification
|
||||
"ALTER TABLE custom_patterns ADD COLUMN category TEXT",
|
||||
"ALTER TABLE custom_patterns ADD COLUMN signal_direction TEXT",
|
||||
# Pattern Explorer — taxonomy tree path
|
||||
"ALTER TABLE custom_patterns ADD COLUMN taxonomy_path TEXT DEFAULT '[]'",
|
||||
]:
|
||||
try:
|
||||
c.execute(_sql)
|
||||
@@ -880,16 +882,17 @@ def update_position_notes(pos_id: str, notes: str):
|
||||
# ── Custom Patterns ────────────────────────────────────────────────────────────
|
||||
|
||||
def seed_builtin_patterns(builtin_patterns: List[Dict[str, Any]]):
|
||||
"""Seed built-in patterns into DB (idempotent — skips existing IDs)."""
|
||||
"""Seed built-in patterns into DB (idempotent). Always updates taxonomy_path."""
|
||||
conn = get_conn()
|
||||
existing = {r[0] for r in conn.execute("SELECT id FROM custom_patterns").fetchall()}
|
||||
for p in builtin_patterns:
|
||||
taxonomy_json = json.dumps(p.get("taxonomy_path", []))
|
||||
if p["id"] not in existing:
|
||||
conn.execute("""INSERT INTO custom_patterns (
|
||||
id, name, description, triggers, keywords, historical_instances,
|
||||
suggested_trades, asset_class, expected_move_pct, probability,
|
||||
horizon_days, source, is_active, updated_at
|
||||
) VALUES (?,?,?,?,?,?,?,?,?,?,?,'builtin',1,datetime('now'))""", (
|
||||
horizon_days, source, is_active, taxonomy_path, updated_at
|
||||
) VALUES (?,?,?,?,?,?,?,?,?,?,?,'builtin',1,?,datetime('now'))""", (
|
||||
p["id"],
|
||||
p.get("name", ""),
|
||||
p.get("description", ""),
|
||||
@@ -901,7 +904,13 @@ def seed_builtin_patterns(builtin_patterns: List[Dict[str, Any]]):
|
||||
p.get("expected_move_pct", 0),
|
||||
p.get("probability", 0.5),
|
||||
p.get("horizon_days", 30),
|
||||
taxonomy_json,
|
||||
))
|
||||
else:
|
||||
conn.execute(
|
||||
"UPDATE custom_patterns SET taxonomy_path=? WHERE id=? AND source='builtin'",
|
||||
(taxonomy_json, p["id"])
|
||||
)
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
@@ -955,6 +964,7 @@ def get_custom_patterns() -> List[Dict[str, Any]]:
|
||||
d = dict(r)
|
||||
for f in ["triggers", "keywords", "historical_instances", "suggested_trades", "ai_evaluation"]:
|
||||
d[f] = json.loads(d.get(f) or "[]")
|
||||
d["taxonomy_path"] = json.loads(d.get("taxonomy_path") or "[]")
|
||||
result.append(d)
|
||||
return result
|
||||
|
||||
|
||||
Reference in New Issue
Block a user