Mercurial
annotate schwab_trader/dashboard_server.py @ 279:b3b547563ec7
Add Google connector service and agent wiki
Implement the C/Seobeo Google Drive and Gmail connector with encrypted OAuth storage, Zenbu authentication, browser testing, AI tool discovery, chunked HTTP decoding, and Bazel coverage. Consolidate repository guidance into progressive wiki documentation and enforce arena-first allocation for new first-party C code.
Co-authored-by: Copilot <[email protected]>
Copilot-Session: 84c338fd-0939-4bb3-b7f3-1062eb213e5d
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Mon, 17 Aug 2026 22:22:36 -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 argparse |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
4 import json |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
5 from http import HTTPStatus |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
6 from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
7 from typing import Any |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
8 from urllib.parse import parse_qs, urlparse |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
9 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
10 from schwab_trader.dashboard import DashboardStore, EvidenceInput, get_config_if_available |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
11 from schwab_trader.schwab_client import SchwabError, get_account, get_account_numbers, get_accounts, load_tokens |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
12 |
|
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 INDEX_HTML = """<!doctype html> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
15 <html lang="en"> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
16 <head> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
17 <meta charset="utf-8"> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
18 <meta name="viewport" content="width=device-width, initial-scale=1"> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
19 <title>Schwab Sentiment Dashboard</title> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
20 <style> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
21 :root { color-scheme: dark; font-family: Inter, system-ui, sans-serif; background: #0b1020; color: #eef2ff; } |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
22 body { margin: 0; } |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
23 header { padding: 24px; background: linear-gradient(135deg, #172554, #0f172a); border-bottom: 1px solid #334155; } |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
24 h1 { margin: 0 0 8px; font-size: 28px; } |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
25 main { display: grid; gap: 16px; grid-template-columns: repeat(auto-fit, minmax(340px, 1fr)); padding: 16px; } |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
26 section { background: #111827; border: 1px solid #334155; border-radius: 14px; padding: 16px; box-shadow: 0 10px 25px #0004; } |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
27 h2 { margin-top: 0; font-size: 18px; } |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
28 label { display: block; margin: 10px 0 4px; color: #cbd5e1; } |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
29 input, textarea, select, button { width: 100%; box-sizing: border-box; border-radius: 8px; border: 1px solid #475569; background: #020617; color: #f8fafc; padding: 10px; } |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
30 button { margin-top: 12px; background: #2563eb; border: 0; font-weight: 700; cursor: pointer; } |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
31 button.secondary { background: #334155; } |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
32 pre { overflow: auto; white-space: pre-wrap; word-break: break-word; background: #020617; padding: 12px; border-radius: 8px; } |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
33 table { width: 100%; border-collapse: collapse; font-size: 13px; } |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
34 th, td { border-bottom: 1px solid #334155; padding: 8px; text-align: left; vertical-align: top; } |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
35 .ok { color: #86efac; } |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
36 .warn { color: #fbbf24; } |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
37 .bad { color: #fca5a5; } |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
38 .span2 { grid-column: 1 / -1; } |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
39 </style> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
40 </head> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
41 <body> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
42 <header> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
43 <h1>Schwab Sentiment Dashboard</h1> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
44 <div>This is local-first and read/paper-trade focused. There is no live-trade endpoint in this dashboard.</div> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
45 </header> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
46 <main> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
47 <section> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
48 <h2>Status</h2> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
49 <button onclick="loadAll()">Refresh</button> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
50 <pre id="status">Loading...</pre> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
51 </section> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
52 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
53 <section> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
54 <h2>Settings</h2> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
55 <label>Profit target %</label><input id="profit_target_pct" type="number" step="0.1"> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
56 <label>Stop loss %</label><input id="stop_loss_pct" type="number" step="0.1"> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
57 <label>Max dollars per paper trade</label><input id="max_trade_dollars" type="number" step="1"> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
58 <label>Minimum confidence</label><input id="min_confidence" type="number" step="0.01" min="0" max="1"> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
59 <button onclick="saveSettings()">Save Settings</button> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
60 <pre id="settingsResult"></pre> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
61 </section> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
62 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
63 <section> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
64 <h2>Add Social Evidence</h2> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
65 <label>Source</label><input id="source" placeholder="reddit"> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
66 <label>Symbol</label><input id="symbol" placeholder="AAPL"> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
67 <label>URL</label><input id="url" placeholder="https://..."> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
68 <label>Engagement</label><input id="engagement" type="number" value="0"> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
69 <label>Text</label><textarea id="text" rows="5" placeholder="$AAPL looks bullish..."></textarea> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
70 <button onclick="addEvidence()">Add Evidence</button> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
71 <pre id="evidenceResult"></pre> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
72 </section> |
|
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 <section> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
75 <h2>Paper Trade</h2> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
76 <label>Action</label><select id="paperAction"><option>BUY</option><option>SELL</option></select> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
77 <label>Symbol</label><input id="paperSymbol" placeholder="AAPL"> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
78 <label>Quantity</label><input id="paperQuantity" type="number" step="0.01" value="1"> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
79 <label>Price</label><input id="paperPrice" type="number" step="0.01"> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
80 <label>Reason</label><input id="paperReason" placeholder="manual paper trade"> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
81 <button onclick="addPaperTrade()">Create Paper Trade</button> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
82 <pre id="paperResult"></pre> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
83 </section> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
84 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
85 <section class="span2"> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
86 <h2>Signals</h2> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
87 <div id="signals"></div> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
88 </section> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
89 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
90 <section> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
91 <h2>Recent Evidence</h2> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
92 <div id="evidence"></div> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
93 </section> |
|
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 <section> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
96 <h2>Paper Trades</h2> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
97 <div id="paperTrades"></div> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
98 </section> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
99 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
100 <section class="span2"> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
101 <h2>Audit Log</h2> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
102 <div id="audit"></div> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
103 </section> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
104 </main> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
105 <script> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
106 async function api(path, options = {}) { |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
107 const response = await fetch(path, { |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
108 headers: {'Content-Type': 'application/json'}, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
109 ...options |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
110 }); |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
111 const body = await response.json(); |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
112 if (!response.ok) throw new Error(body.error || response.statusText); |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
113 return body; |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
114 } |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
115 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
116 function json(id, value) { |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
117 document.getElementById(id).textContent = JSON.stringify(value, null, 2); |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
118 } |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
119 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
120 function table(rows, cols) { |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
121 if (!rows.length) return '<p class="warn">No data yet.</p>'; |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
122 return '<table><thead><tr>' + cols.map(c => `<th>${c}</th>`).join('') + |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
123 '</tr></thead><tbody>' + rows.map(row => '<tr>' + cols.map(c => `<td>${row[c] ?? ''}</td>`).join('') + '</tr>').join('') + '</tbody></table>'; |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
124 } |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
125 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
126 async function loadAll() { |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
127 const [status, settings, signals, evidence, paperTrades, audit] = await Promise.all([ |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
128 api('/api/status'), api('/api/settings'), api('/api/signals'), |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
129 api('/api/evidence'), api('/api/paper-trades'), api('/api/audit') |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
130 ]); |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
131 json('status', status); |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
132 for (const key of ['profit_target_pct', 'stop_loss_pct', 'max_trade_dollars', 'min_confidence']) { |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
133 document.getElementById(key).value = settings[key]; |
|
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 document.getElementById('signals').innerHTML = table(signals, ['symbol', 'action', 'sentiment_score', 'confidence', 'evidence_count', 'source_count', 'summary']); |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
136 document.getElementById('evidence').innerHTML = table(evidence, ['id', 'source', 'symbol', 'sentiment_score', 'engagement', 'text']); |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
137 document.getElementById('paperTrades').innerHTML = table(paperTrades, ['id', 'symbol', 'action', 'quantity', 'price', 'notional', 'status', 'reason']); |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
138 document.getElementById('audit').innerHTML = table(audit, ['id', 'event_type', 'message', 'created_at']); |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
139 } |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
140 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
141 async function saveSettings() { |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
142 try { |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
143 const body = {}; |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
144 for (const key of ['profit_target_pct', 'stop_loss_pct', 'max_trade_dollars', 'min_confidence']) { |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
145 body[key] = Number(document.getElementById(key).value); |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
146 } |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
147 json('settingsResult', await api('/api/settings', {method: 'POST', body: JSON.stringify(body)})); |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
148 await loadAll(); |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
149 } catch (error) { json('settingsResult', {error: error.message}); } |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
150 } |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
151 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
152 async function addEvidence() { |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
153 try { |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
154 const body = { |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
155 source: document.getElementById('source').value, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
156 symbol: document.getElementById('symbol').value, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
157 url: document.getElementById('url').value, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
158 engagement: Number(document.getElementById('engagement').value), |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
159 text: document.getElementById('text').value |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
160 }; |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
161 json('evidenceResult', await api('/api/evidence', {method: 'POST', body: JSON.stringify(body)})); |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
162 await loadAll(); |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
163 } catch (error) { json('evidenceResult', {error: error.message}); } |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
164 } |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
165 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
166 async function addPaperTrade() { |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
167 try { |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
168 const body = { |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
169 action: document.getElementById('paperAction').value, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
170 symbol: document.getElementById('paperSymbol').value, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
171 quantity: Number(document.getElementById('paperQuantity').value), |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
172 price: Number(document.getElementById('paperPrice').value), |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
173 reason: document.getElementById('paperReason').value |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
174 }; |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
175 json('paperResult', await api('/api/paper-trades', {method: 'POST', body: JSON.stringify(body)})); |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
176 await loadAll(); |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
177 } catch (error) { json('paperResult', {error: error.message}); } |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
178 } |
|
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 loadAll(); |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
181 </script> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
182 </body> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
183 </html> |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
184 """ |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
185 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
186 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
187 def create_handler(store: DashboardStore) -> type[BaseHTTPRequestHandler]: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
188 class DashboardHandler(BaseHTTPRequestHandler): |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
189 server_version = "SchwabDashboard/0.1" |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
190 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
191 def do_GET(self) -> None: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
192 try: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
193 parsed = urlparse(self.path) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
194 query = parse_qs(parsed.query) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
195 if parsed.path == "/": |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
196 self._send_html(INDEX_HTML) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
197 elif parsed.path == "/api/status": |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
198 self._send_json(store.get_status()) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
199 elif parsed.path == "/api/settings": |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
200 self._send_json(store.get_settings()) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
201 elif parsed.path == "/api/evidence": |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
202 self._send_json(store.list_evidence()) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
203 elif parsed.path == "/api/signals": |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
204 self._send_json(store.list_signals()) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
205 elif parsed.path == "/api/paper-trades": |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
206 self._send_json(store.list_paper_trades()) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
207 elif parsed.path == "/api/audit": |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
208 self._send_json(store.list_audit()) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
209 elif parsed.path == "/api/schwab/account-numbers": |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
210 self._send_json(_load_schwab_account_numbers()) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
211 elif parsed.path == "/api/schwab/accounts": |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
212 fields = "positions" if query.get("positions") == ["1"] else None |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
213 self._send_json(_load_schwab_accounts(fields)) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
214 elif parsed.path == "/api/schwab/account": |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
215 account_hash = query.get("account_hash", [""])[0] |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
216 fields = "positions" if query.get("positions") == ["1"] else None |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
217 self._send_json(_load_schwab_account(account_hash, fields)) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
218 else: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
219 self._send_error(HTTPStatus.NOT_FOUND, "Not found") |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
220 except (ValueError, SchwabError) as error: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
221 self._send_error(HTTPStatus.BAD_REQUEST, str(error)) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
222 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
223 def do_POST(self) -> None: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
224 try: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
225 parsed = urlparse(self.path) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
226 payload = self._read_json() |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
227 if parsed.path == "/api/settings": |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
228 self._send_json(store.update_settings(payload)) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
229 elif parsed.path == "/api/evidence": |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
230 result = store.add_evidence( |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
231 EvidenceInput( |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
232 source=str(payload.get("source", "")), |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
233 symbol=str(payload["symbol"]) if payload.get("symbol") else None, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
234 url=str(payload["url"]) if payload.get("url") else None, |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
235 text=str(payload.get("text", "")), |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
236 engagement=float(payload.get("engagement", 0)), |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
237 raw=payload.get("raw") if isinstance(payload.get("raw"), dict) else None, |
|
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 ) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
240 self._send_json(result, HTTPStatus.CREATED) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
241 elif parsed.path == "/api/paper-trades": |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
242 self._send_json(store.add_paper_trade(payload), HTTPStatus.CREATED) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
243 else: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
244 self._send_error(HTTPStatus.NOT_FOUND, "Not found") |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
245 except (ValueError, KeyError, SchwabError) as error: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
246 self._send_error(HTTPStatus.BAD_REQUEST, str(error)) |
|
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 def log_message(self, format: str, *args: Any) -> None: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
249 print(f"[dashboard] {self.address_string()} - {format % args}") |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
250 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
251 def _read_json(self) -> dict[str, Any]: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
252 length = int(self.headers.get("Content-Length", "0")) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
253 if length <= 0: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
254 return {} |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
255 raw = self.rfile.read(length).decode("utf-8") |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
256 value = json.loads(raw) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
257 if not isinstance(value, dict): |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
258 raise ValueError("JSON body must be an object") |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
259 return value |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
260 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
261 def _send_html(self, body: str) -> None: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
262 data = body.encode("utf-8") |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
263 self.send_response(HTTPStatus.OK) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
264 self.send_header("Content-Type", "text/html; charset=utf-8") |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
265 self.send_header("Content-Length", str(len(data))) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
266 self.end_headers() |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
267 self.wfile.write(data) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
268 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
269 def _send_json(self, body: Any, status: HTTPStatus = HTTPStatus.OK) -> None: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
270 data = json.dumps(body, indent=2, sort_keys=True).encode("utf-8") |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
271 self.send_response(status) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
272 self.send_header("Content-Type", "application/json; charset=utf-8") |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
273 self.send_header("Content-Length", str(len(data))) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
274 self.end_headers() |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
275 self.wfile.write(data) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
276 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
277 def _send_error(self, status: HTTPStatus, message: str) -> None: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
278 self._send_json({"error": message}, status) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
279 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
280 return DashboardHandler |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
281 |
|
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 def _load_schwab_account_numbers() -> Any: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
284 config, access_token = _load_schwab_access_token() |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
285 return get_account_numbers(access_token).body |
|
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 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
288 def _load_schwab_accounts(fields: str | None) -> Any: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
289 config, access_token = _load_schwab_access_token() |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
290 return get_accounts(access_token, fields).body |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
291 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
292 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
293 def _load_schwab_account(account_hash: str, fields: str | None) -> Any: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
294 if not account_hash: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
295 raise ValueError("account_hash is required") |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
296 config, access_token = _load_schwab_access_token() |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
297 return get_account(access_token, account_hash, fields).body |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
298 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
299 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
300 def _load_schwab_access_token() -> tuple[Any, str]: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
301 config = get_config_if_available() |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
302 if config is None: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
303 raise SchwabError("Schwab environment is not configured") |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
304 tokens = load_tokens(config.token_file) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
305 access_token = tokens.get("access_token") |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
306 if not access_token: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
307 raise SchwabError(f"No access_token in {config.token_file}") |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
308 return config, access_token |
|
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 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
311 def run(host: str, port: int, db_path: str | None = None) -> None: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
312 store = DashboardStore(db_path) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
313 server = ThreadingHTTPServer((host, port), create_handler(store)) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
314 print(f"Schwab dashboard listening on http://{host}:{port}") |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
315 print("Live trading is disabled in this dashboard.") |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
316 server.serve_forever() |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
317 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
318 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
319 def main() -> int: |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
320 parser = argparse.ArgumentParser(description="Run the local Schwab sentiment dashboard") |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
321 parser.add_argument("--host", default="127.0.0.1") |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
322 parser.add_argument("--port", default=8765, type=int) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
323 parser.add_argument("--db", help="SQLite dashboard DB path") |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
324 args = parser.parse_args() |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
325 run(args.host, args.port, args.db) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
326 return 0 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
327 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
328 |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
329 if __name__ == "__main__": |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
330 raise SystemExit(main()) |
|
eb8b4230fdb9
[schwab-trader] Add guarded trading experiment
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
331 |