Mercurial
annotate schwab_trader/dashboard.py @ 270:358dd5950985
sync production config on every deploy
Always install the ignored repository .config into /etc/mrjunejune before promoting the new bundle.
Co-authored-by: Copilot <[email protected]>
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Fri, 07 Aug 2026 13:16:47 -0700 |
| parents | eb8b4230fdb9 |
| children |
| rev | line source |
|---|---|
|
220
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
1 from __future__ import annotations |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
2 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
3 import json |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
4 import os |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
5 import re |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
6 import sqlite3 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
7 import time |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
8 from dataclasses import dataclass |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
9 from pathlib import Path |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
10 from typing import Any |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
11 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
12 from schwab_trader.schwab_client import DEFAULT_TOKEN_FILE, SchwabConfig, load_tokens |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
13 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
14 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
15 DEFAULT_DASHBOARD_DB = "~/.local/share/zenbu/schwab_trader/dashboard.db" |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
16 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
17 DEFAULT_SETTINGS: dict[str, Any] = { |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
18 "profit_target_pct": 3.0, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
19 "stop_loss_pct": 2.0, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
20 "max_trade_dollars": 500.0, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
21 "max_account_pct": 2.0, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
22 "max_open_positions": 3, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
23 "min_confidence": 0.60, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
24 "min_evidence_count": 3, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
25 "min_source_count": 2, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
26 "cooldown_minutes": 60, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
27 "market_hours_only": True, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
28 "max_daily_loss_dollars": 250.0, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
29 "day_trade_limit": 3, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
30 "live_trading_enabled": False, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
31 "require_manual_confirmation": True, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
32 "llm_enabled": False, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
33 "allowlist": [], |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
34 "blocklist": [], |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
35 } |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
36 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
37 POSITIVE_WORDS = { |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
38 "beat", |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
39 "beats", |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
40 "bull", |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
41 "bullish", |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
42 "buy", |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
43 "calls", |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
44 "growth", |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
45 "hype", |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
46 "moon", |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
47 "mooning", |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
48 "profit", |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
49 "rally", |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
50 "strong", |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
51 "surge", |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
52 "up", |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
53 "winner", |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
54 } |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
55 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
56 NEGATIVE_WORDS = { |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
57 "bear", |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
58 "bearish", |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
59 "crash", |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
60 "dump", |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
61 "fall", |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
62 "falling", |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
63 "fraud", |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
64 "lawsuit", |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
65 "loss", |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
66 "miss", |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
67 "puts", |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
68 "risk", |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
69 "sell", |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
70 "short", |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
71 "weak", |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
72 } |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
73 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
74 SYMBOL_RE = re.compile(r"(?<![A-Z0-9])\$?([A-Z]{1,5})(?![A-Z0-9])") |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
75 COMMON_WORDS = { |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
76 "A", |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
77 "AI", |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
78 "AM", |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
79 "API", |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
80 "CEO", |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
81 "CFO", |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
82 "DD", |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
83 "ETF", |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
84 "GDP", |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
85 "IPO", |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
86 "IRS", |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
87 "LLM", |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
88 "PDT", |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
89 "SEC", |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
90 "USA", |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
91 "USD", |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
92 } |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
93 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
94 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
95 @dataclass(frozen=True) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
96 class EvidenceInput: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
97 source: str |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
98 text: str |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
99 symbol: str | None = None |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
100 url: str | None = None |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
101 engagement: float = 0.0 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
102 raw: dict[str, Any] | None = None |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
103 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
104 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
105 class DashboardStore: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
106 def __init__(self, db_path: Path | str | None = None) -> None: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
107 if db_path is None: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
108 db_path = os.environ.get("SCHWAB_DASHBOARD_DB", DEFAULT_DASHBOARD_DB) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
109 self.db_path = Path(db_path).expanduser() |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
110 self.db_path.parent.mkdir(parents=True, exist_ok=True) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
111 self._init_db() |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
112 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
113 def get_status(self) -> dict[str, Any]: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
114 token_file = Path(os.environ.get("SCHWAB_TOKEN_FILE", DEFAULT_TOKEN_FILE)).expanduser() |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
115 token_status: dict[str, Any] = { |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
116 "path": str(token_file), |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
117 "exists": token_file.exists(), |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
118 "access_token_present": False, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
119 "refresh_token_present": False, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
120 "saved_at": None, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
121 "age_seconds": None, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
122 } |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
123 if token_file.exists(): |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
124 try: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
125 tokens = load_tokens(token_file) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
126 saved_at = tokens.get("saved_at") |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
127 token_status.update( |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
128 { |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
129 "access_token_present": bool(tokens.get("access_token")), |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
130 "refresh_token_present": bool(tokens.get("refresh_token")), |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
131 "saved_at": saved_at, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
132 "age_seconds": int(time.time()) - int(saved_at) if saved_at else None, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
133 } |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
134 ) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
135 except (OSError, ValueError, TypeError) as error: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
136 token_status["error"] = str(error) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
137 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
138 env_status = { |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
139 "SCHWAB_APP_KEY": bool(os.environ.get("SCHWAB_APP_KEY")), |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
140 "SCHWAB_APP_SECRET": bool(os.environ.get("SCHWAB_APP_SECRET")), |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
141 "SCHWAB_REDIRECT_URI": bool(os.environ.get("SCHWAB_REDIRECT_URI")), |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
142 } |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
143 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
144 return { |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
145 "service": "schwab-dashboard", |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
146 "database": str(self.db_path), |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
147 "env": env_status, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
148 "tokens": token_status, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
149 "live_trading_enabled": False, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
150 "live_trading_note": "Dashboard has no live-trade endpoint; use CLI dry-run/manual confirmation flow.", |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
151 "counts": self.get_counts(), |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
152 } |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
153 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
154 def get_counts(self) -> dict[str, int]: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
155 with self._connect() as conn: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
156 return { |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
157 "evidence": self._count(conn, "evidence"), |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
158 "signals": self._count(conn, "signals"), |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
159 "paper_trades": self._count(conn, "paper_trades"), |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
160 "audit_events": self._count(conn, "audit"), |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
161 } |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
162 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
163 def get_settings(self) -> dict[str, Any]: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
164 settings = dict(DEFAULT_SETTINGS) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
165 with self._connect() as conn: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
166 for row in conn.execute("SELECT key, value_json FROM settings"): |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
167 settings[row["key"]] = json.loads(row["value_json"]) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
168 return settings |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
169 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
170 def update_settings(self, updates: dict[str, Any]) -> dict[str, Any]: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
171 allowed = set(DEFAULT_SETTINGS) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
172 unknown = sorted(set(updates) - allowed) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
173 if unknown: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
174 raise ValueError("Unknown settings: " + ", ".join(unknown)) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
175 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
176 current = self.get_settings() |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
177 current.update(updates) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
178 self._validate_settings(current) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
179 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
180 with self._connect() as conn: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
181 for key, value in current.items(): |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
182 conn.execute( |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
183 """ |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
184 INSERT INTO settings(key, value_json) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
185 VALUES (?, ?) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
186 ON CONFLICT(key) DO UPDATE SET value_json = excluded.value_json |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
187 """, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
188 (key, json.dumps(value, sort_keys=True)), |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
189 ) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
190 conn.commit() |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
191 self.add_audit("settings.updated", "Dashboard settings updated", updates) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
192 return current |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
193 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
194 def add_evidence(self, item: EvidenceInput) -> dict[str, Any]: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
195 source = item.source.strip().lower() |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
196 text = item.text.strip() |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
197 if not source: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
198 raise ValueError("source is required") |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
199 if not text: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
200 raise ValueError("text is required") |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
201 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
202 symbol = normalize_symbol(item.symbol) if item.symbol else extract_symbol(text) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
203 if not symbol: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
204 raise ValueError("symbol is required or must be detectable as a ticker in text") |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
205 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
206 sentiment_score = score_sentiment(text) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
207 created_at = int(time.time()) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
208 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
209 with self._connect() as conn: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
210 cursor = conn.execute( |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
211 """ |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
212 INSERT INTO evidence( |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
213 source, symbol, url, text, engagement, sentiment_score, raw_json, created_at |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
214 ) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
215 VALUES (?, ?, ?, ?, ?, ?, ?, ?) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
216 """, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
217 ( |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
218 source, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
219 symbol, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
220 item.url, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
221 text, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
222 float(item.engagement), |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
223 sentiment_score, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
224 json.dumps(item.raw or {}, sort_keys=True), |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
225 created_at, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
226 ), |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
227 ) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
228 evidence_id = int(cursor.lastrowid) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
229 conn.commit() |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
230 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
231 signal = self.recompute_signal(symbol) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
232 self.add_audit( |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
233 "evidence.added", |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
234 f"Added {source} evidence for {symbol}", |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
235 {"evidence_id": evidence_id, "symbol": symbol, "signal": signal}, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
236 ) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
237 return {"id": evidence_id, "symbol": symbol, "sentiment_score": sentiment_score, "signal": signal} |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
238 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
239 def list_evidence(self, limit: int = 100) -> list[dict[str, Any]]: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
240 with self._connect() as conn: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
241 rows = conn.execute( |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
242 """ |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
243 SELECT id, source, symbol, url, text, engagement, sentiment_score, created_at |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
244 FROM evidence |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
245 ORDER BY id DESC |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
246 LIMIT ? |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
247 """, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
248 (limit,), |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
249 ).fetchall() |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
250 return [dict(row) for row in rows] |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
251 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
252 def recompute_signal(self, symbol: str) -> dict[str, Any]: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
253 symbol = normalize_symbol(symbol) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
254 settings = self.get_settings() |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
255 with self._connect() as conn: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
256 rows = conn.execute( |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
257 """ |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
258 SELECT source, sentiment_score, engagement, created_at |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
259 FROM evidence |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
260 WHERE symbol = ? |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
261 ORDER BY id DESC |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
262 LIMIT 100 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
263 """, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
264 (symbol,), |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
265 ).fetchall() |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
266 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
267 evidence_count = len(rows) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
268 source_count = len({row["source"] for row in rows}) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
269 weighted_total = 0.0 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
270 weight_sum = 0.0 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
271 for row in rows: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
272 engagement_weight = min(5.0, 1.0 + max(0.0, float(row["engagement"])) / 100.0) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
273 weighted_total += float(row["sentiment_score"]) * engagement_weight |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
274 weight_sum += engagement_weight |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
275 sentiment_score = weighted_total / weight_sum if weight_sum else 0.0 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
276 confidence = compute_confidence(sentiment_score, evidence_count, source_count) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
277 action = decide_signal_action(symbol, sentiment_score, confidence, evidence_count, source_count, settings) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
278 summary = summarize_signal(symbol, sentiment_score, confidence, evidence_count, source_count, action) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
279 updated_at = int(time.time()) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
280 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
281 conn.execute( |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
282 """ |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
283 INSERT INTO signals( |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
284 symbol, sentiment_score, confidence, evidence_count, source_count, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
285 action, summary, updated_at |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
286 ) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
287 VALUES (?, ?, ?, ?, ?, ?, ?, ?) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
288 ON CONFLICT(symbol) DO UPDATE SET |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
289 sentiment_score = excluded.sentiment_score, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
290 confidence = excluded.confidence, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
291 evidence_count = excluded.evidence_count, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
292 source_count = excluded.source_count, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
293 action = excluded.action, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
294 summary = excluded.summary, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
295 updated_at = excluded.updated_at |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
296 """, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
297 ( |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
298 symbol, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
299 sentiment_score, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
300 confidence, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
301 evidence_count, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
302 source_count, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
303 action, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
304 summary, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
305 updated_at, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
306 ), |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
307 ) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
308 conn.commit() |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
309 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
310 return { |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
311 "symbol": symbol, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
312 "sentiment_score": round(sentiment_score, 4), |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
313 "confidence": round(confidence, 4), |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
314 "evidence_count": evidence_count, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
315 "source_count": source_count, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
316 "action": action, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
317 "summary": summary, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
318 "updated_at": updated_at, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
319 } |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
320 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
321 def list_signals(self) -> list[dict[str, Any]]: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
322 with self._connect() as conn: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
323 rows = conn.execute( |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
324 """ |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
325 SELECT symbol, sentiment_score, confidence, evidence_count, source_count, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
326 action, summary, updated_at |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
327 FROM signals |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
328 ORDER BY confidence DESC, updated_at DESC |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
329 """ |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
330 ).fetchall() |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
331 return [dict(row) for row in rows] |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
332 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
333 def add_paper_trade(self, payload: dict[str, Any]) -> dict[str, Any]: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
334 symbol = normalize_symbol(str(payload.get("symbol", ""))) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
335 action = str(payload.get("action", "")).upper() |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
336 quantity = float(payload.get("quantity", 0)) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
337 price = float(payload.get("price", 0)) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
338 reason = str(payload.get("reason", "manual paper trade")).strip() |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
339 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
340 if action not in {"BUY", "SELL"}: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
341 raise ValueError("action must be BUY or SELL") |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
342 if not symbol: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
343 raise ValueError("symbol is required") |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
344 if quantity <= 0: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
345 raise ValueError("quantity must be greater than zero") |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
346 if price <= 0: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
347 raise ValueError("price must be greater than zero") |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
348 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
349 settings = self.get_settings() |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
350 notional = quantity * price |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
351 status = "accepted" |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
352 if notional > float(settings["max_trade_dollars"]): |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
353 status = "rejected_max_trade_dollars" |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
354 elif symbol in {normalize_symbol(s) for s in settings["blocklist"]}: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
355 status = "rejected_blocklist" |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
356 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
357 created_at = int(time.time()) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
358 with self._connect() as conn: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
359 cursor = conn.execute( |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
360 """ |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
361 INSERT INTO paper_trades(symbol, action, quantity, price, notional, status, reason, created_at) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
362 VALUES (?, ?, ?, ?, ?, ?, ?, ?) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
363 """, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
364 (symbol, action, quantity, price, notional, status, reason, created_at), |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
365 ) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
366 trade_id = int(cursor.lastrowid) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
367 conn.commit() |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
368 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
369 result = { |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
370 "id": trade_id, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
371 "symbol": symbol, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
372 "action": action, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
373 "quantity": quantity, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
374 "price": price, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
375 "notional": notional, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
376 "status": status, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
377 "reason": reason, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
378 "created_at": created_at, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
379 } |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
380 self.add_audit("paper_trade.created", f"Paper trade {status}: {action} {quantity} {symbol}", result) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
381 return result |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
382 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
383 def list_paper_trades(self, limit: int = 100) -> list[dict[str, Any]]: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
384 with self._connect() as conn: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
385 rows = conn.execute( |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
386 """ |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
387 SELECT id, symbol, action, quantity, price, notional, status, reason, created_at |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
388 FROM paper_trades |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
389 ORDER BY id DESC |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
390 LIMIT ? |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
391 """, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
392 (limit,), |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
393 ).fetchall() |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
394 return [dict(row) for row in rows] |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
395 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
396 def add_audit(self, event_type: str, message: str, payload: dict[str, Any] | None = None) -> None: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
397 with self._connect() as conn: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
398 conn.execute( |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
399 """ |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
400 INSERT INTO audit(event_type, message, payload_json, created_at) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
401 VALUES (?, ?, ?, ?) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
402 """, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
403 (event_type, message, json.dumps(payload or {}, sort_keys=True), int(time.time())), |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
404 ) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
405 conn.commit() |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
406 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
407 def list_audit(self, limit: int = 100) -> list[dict[str, Any]]: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
408 with self._connect() as conn: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
409 rows = conn.execute( |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
410 """ |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
411 SELECT id, event_type, message, payload_json, created_at |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
412 FROM audit |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
413 ORDER BY id DESC |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
414 LIMIT ? |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
415 """, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
416 (limit,), |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
417 ).fetchall() |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
418 events = [] |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
419 for row in rows: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
420 event = dict(row) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
421 event["payload"] = json.loads(event.pop("payload_json")) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
422 events.append(event) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
423 return events |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
424 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
425 def _init_db(self) -> None: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
426 with self._connect() as conn: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
427 conn.executescript( |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
428 """ |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
429 CREATE TABLE IF NOT EXISTS settings ( |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
430 key TEXT PRIMARY KEY, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
431 value_json TEXT NOT NULL |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
432 ); |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
433 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
434 CREATE TABLE IF NOT EXISTS evidence ( |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
435 id INTEGER PRIMARY KEY AUTOINCREMENT, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
436 source TEXT NOT NULL, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
437 symbol TEXT NOT NULL, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
438 url TEXT, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
439 text TEXT NOT NULL, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
440 engagement REAL NOT NULL DEFAULT 0, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
441 sentiment_score REAL NOT NULL, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
442 raw_json TEXT NOT NULL DEFAULT '{}', |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
443 created_at INTEGER NOT NULL |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
444 ); |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
445 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
446 CREATE INDEX IF NOT EXISTS idx_evidence_symbol_created |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
447 ON evidence(symbol, created_at); |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
448 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
449 CREATE TABLE IF NOT EXISTS signals ( |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
450 symbol TEXT PRIMARY KEY, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
451 sentiment_score REAL NOT NULL, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
452 confidence REAL NOT NULL, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
453 evidence_count INTEGER NOT NULL, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
454 source_count INTEGER NOT NULL, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
455 action TEXT NOT NULL, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
456 summary TEXT NOT NULL, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
457 updated_at INTEGER NOT NULL |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
458 ); |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
459 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
460 CREATE TABLE IF NOT EXISTS paper_trades ( |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
461 id INTEGER PRIMARY KEY AUTOINCREMENT, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
462 symbol TEXT NOT NULL, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
463 action TEXT NOT NULL, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
464 quantity REAL NOT NULL, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
465 price REAL NOT NULL, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
466 notional REAL NOT NULL, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
467 status TEXT NOT NULL, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
468 reason TEXT NOT NULL, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
469 created_at INTEGER NOT NULL |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
470 ); |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
471 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
472 CREATE TABLE IF NOT EXISTS audit ( |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
473 id INTEGER PRIMARY KEY AUTOINCREMENT, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
474 event_type TEXT NOT NULL, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
475 message TEXT NOT NULL, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
476 payload_json TEXT NOT NULL, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
477 created_at INTEGER NOT NULL |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
478 ); |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
479 """ |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
480 ) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
481 for key, value in DEFAULT_SETTINGS.items(): |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
482 conn.execute( |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
483 "INSERT OR IGNORE INTO settings(key, value_json) VALUES (?, ?)", |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
484 (key, json.dumps(value, sort_keys=True)), |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
485 ) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
486 conn.commit() |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
487 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
488 def _connect(self) -> sqlite3.Connection: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
489 conn = sqlite3.connect(self.db_path) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
490 conn.row_factory = sqlite3.Row |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
491 return conn |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
492 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
493 @staticmethod |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
494 def _count(conn: sqlite3.Connection, table: str) -> int: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
495 return int(conn.execute(f"SELECT COUNT(*) FROM {table}").fetchone()[0]) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
496 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
497 @staticmethod |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
498 def _validate_settings(settings: dict[str, Any]) -> None: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
499 positive_numbers = [ |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
500 "profit_target_pct", |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
501 "stop_loss_pct", |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
502 "max_trade_dollars", |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
503 "max_account_pct", |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
504 "max_daily_loss_dollars", |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
505 ] |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
506 for key in positive_numbers: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
507 if float(settings[key]) <= 0: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
508 raise ValueError(f"{key} must be greater than zero") |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
509 if not 0 <= float(settings["min_confidence"]) <= 1: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
510 raise ValueError("min_confidence must be between 0 and 1") |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
511 if int(settings["min_evidence_count"]) < 1: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
512 raise ValueError("min_evidence_count must be at least 1") |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
513 if int(settings["min_source_count"]) < 1: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
514 raise ValueError("min_source_count must be at least 1") |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
515 if bool(settings["live_trading_enabled"]): |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
516 raise ValueError("live_trading_enabled cannot be enabled from the dashboard") |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
517 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
518 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
519 def normalize_symbol(value: str) -> str: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
520 symbol = value.strip().upper().lstrip("$") |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
521 if not re.fullmatch(r"[A-Z]{1,5}", symbol): |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
522 raise ValueError("symbol must be 1-5 letters") |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
523 return symbol |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
524 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
525 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
526 def extract_symbol(text: str) -> str | None: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
527 for match in SYMBOL_RE.finditer(text.upper()): |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
528 symbol = match.group(1) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
529 if symbol not in COMMON_WORDS: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
530 return symbol |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
531 return None |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
532 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
533 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
534 def score_sentiment(text: str) -> float: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
535 words = re.findall(r"[a-zA-Z']+", text.lower()) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
536 positive = sum(1 for word in words if word in POSITIVE_WORDS) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
537 negative = sum(1 for word in words if word in NEGATIVE_WORDS) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
538 total = positive + negative |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
539 if total == 0: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
540 return 0.0 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
541 return max(-1.0, min(1.0, (positive - negative) / total)) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
542 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
543 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
544 def compute_confidence(sentiment_score: float, evidence_count: int, source_count: int) -> float: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
545 evidence_component = min(0.35, evidence_count * 0.07) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
546 source_component = min(0.25, source_count * 0.10) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
547 sentiment_component = min(0.20, abs(sentiment_score) * 0.20) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
548 return min(0.95, 0.20 + evidence_component + source_component + sentiment_component) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
549 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
550 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
551 def decide_signal_action( |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
552 symbol: str, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
553 sentiment_score: float, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
554 confidence: float, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
555 evidence_count: int, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
556 source_count: int, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
557 settings: dict[str, Any], |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
558 ) -> str: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
559 blocklist = {normalize_symbol(item) for item in settings.get("blocklist", [])} |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
560 allowlist = {normalize_symbol(item) for item in settings.get("allowlist", [])} |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
561 if symbol in blocklist: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
562 return "NO_TRADE_BLOCKED" |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
563 if allowlist and symbol not in allowlist: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
564 return "NO_TRADE_NOT_ALLOWLISTED" |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
565 if evidence_count < int(settings["min_evidence_count"]): |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
566 return "NO_TRADE_NEEDS_EVIDENCE" |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
567 if source_count < int(settings["min_source_count"]): |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
568 return "NO_TRADE_NEEDS_SOURCE_DIVERSITY" |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
569 if confidence < float(settings["min_confidence"]): |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
570 return "NO_TRADE_LOW_CONFIDENCE" |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
571 if sentiment_score >= 0.25: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
572 return "CONSIDER_BUY" |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
573 if sentiment_score <= -0.25: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
574 return "CONSIDER_SELL" |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
575 return "WATCH" |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
576 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
577 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
578 def summarize_signal( |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
579 symbol: str, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
580 sentiment_score: float, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
581 confidence: float, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
582 evidence_count: int, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
583 source_count: int, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
584 action: str, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
585 ) -> str: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
586 direction = "positive" if sentiment_score > 0 else "negative" if sentiment_score < 0 else "neutral" |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
587 return ( |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
588 f"{symbol} has {direction} social sentiment from {evidence_count} evidence item(s) " |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
589 f"across {source_count} source(s). Confidence is {confidence:.0%}. Action: {action}." |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
590 ) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
591 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
592 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
593 def get_config_if_available() -> SchwabConfig | None: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
594 try: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
595 return SchwabConfig.from_env() |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
596 except Exception: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
597 return None |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
598 |