Compare commits
2 Commits
2294f5bc07
...
026b470b31
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
026b470b31 | ||
|
|
6a407cf216 |
63
analyze.py
63
analyze.py
@@ -83,11 +83,11 @@ ALERT_THRESHOLD = 0.35 # signal_score > this → alert
|
||||
# Claude metrics
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
METRICS_FILE = Path(__file__).parent / "metrics.json"
|
||||
METRICS_FILE = Path(os.getenv("DATA_DIR", str(Path(__file__).parent / "data"))) / "metrics.json"
|
||||
|
||||
# Pricing: Claude Haiku 4.5 — https://www.anthropic.com/pricing
|
||||
_PRICE_INPUT_PER_TOKEN = 0.80 / 1_000_000 # $0.80 per MTok
|
||||
_PRICE_OUTPUT_PER_TOKEN = 4.00 / 1_000_000 # $4.00 per MTok
|
||||
# Pricing: Claude 3 Haiku — https://www.anthropic.com/pricing
|
||||
_PRICE_INPUT_PER_TOKEN = 0.25 / 1_000_000 # $0.25 per MTok
|
||||
_PRICE_OUTPUT_PER_TOKEN = 1.25 / 1_000_000 # $1.25 per MTok
|
||||
|
||||
|
||||
def calc_cost(input_tokens: int, output_tokens: int) -> float:
|
||||
@@ -270,7 +270,7 @@ Fields:
|
||||
|
||||
try:
|
||||
msg = client.messages.create(
|
||||
model="claude-haiku-4-5",
|
||||
model="claude-3-haiku-20240307",
|
||||
max_tokens=256,
|
||||
messages=[{"role": "user", "content": prompt}],
|
||||
)
|
||||
@@ -372,6 +372,7 @@ def analyze_articles(
|
||||
dry_run: bool = False,
|
||||
use_claude: bool = True,
|
||||
auto_fetch: bool = True,
|
||||
max_claude_calls: int = 50,
|
||||
) -> None:
|
||||
db = get_db()
|
||||
migrate_db(db)
|
||||
@@ -486,6 +487,16 @@ def analyze_articles(
|
||||
now = int(time.time())
|
||||
signals_written = 0
|
||||
alerts_triggered = 0
|
||||
claude_calls_this_run = 0
|
||||
|
||||
# Daily spend guard — read current metrics before starting
|
||||
_existing = {}
|
||||
if METRICS_FILE.exists():
|
||||
try:
|
||||
_existing = json.loads(METRICS_FILE.read_text())
|
||||
except Exception:
|
||||
pass
|
||||
DAILY_COST_CAP = float(os.getenv("CLAUDE_DAILY_CAP_USD", "2.0"))
|
||||
|
||||
for row, matches, cov, full_text in final:
|
||||
slug = row["slug"]
|
||||
@@ -507,10 +518,19 @@ def analyze_articles(
|
||||
# ------------------------------------------------------------------
|
||||
claude_data: dict = {}
|
||||
if use_claude and not dry_run and os.environ.get("ANTHROPIC_API_KEY"):
|
||||
print(f" [claude] {slug[:50]}")
|
||||
claude_data, _in_tok, _out_tok = claude_extract(title, full_text, list(matches.keys()))
|
||||
if _in_tok:
|
||||
update_metrics(_in_tok, _out_tok)
|
||||
if claude_calls_this_run >= max_claude_calls:
|
||||
print(f" [claude] ⚠️ per-run cap ({max_claude_calls}) reached — skipping remaining articles")
|
||||
use_claude = False
|
||||
elif _existing.get("total_cost_usd", 0.0) >= DAILY_COST_CAP:
|
||||
print(f" [claude] ⚠️ daily spend cap ${DAILY_COST_CAP} reached — skipping Claude for remaining articles")
|
||||
use_claude = False
|
||||
else:
|
||||
print(f" [claude] {slug[:50]}")
|
||||
claude_data, _in_tok, _out_tok = claude_extract(title, full_text, list(matches.keys()))
|
||||
if _in_tok:
|
||||
update_metrics(_in_tok, _out_tok)
|
||||
_existing["total_cost_usd"] = _existing.get("total_cost_usd", 0.0) + calc_cost(_in_tok, _out_tok)
|
||||
claude_calls_this_run += 1
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Phase 6 — yfinance momentum + scoring
|
||||
@@ -587,9 +607,28 @@ def analyze_articles(
|
||||
|
||||
def main() -> None:
|
||||
import sys
|
||||
force = "--force" in sys.argv
|
||||
dry_run = "--dry" in sys.argv
|
||||
analyze_articles(force=force, dry_run=dry_run)
|
||||
force = "--force" in sys.argv
|
||||
dry_run = "--dry-run" in sys.argv or "--dry" in sys.argv
|
||||
no_claude = "--no-claude" in sys.argv
|
||||
|
||||
# --max-claude=N override per-run cap
|
||||
max_calls = 50
|
||||
for arg in sys.argv:
|
||||
if arg.startswith("--max-claude="):
|
||||
try:
|
||||
max_calls = int(arg.split("=", 1)[1])
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
if force:
|
||||
print(f"[analyze] ⚠️ --force mode: re-analyzing ALL articles (claude cap={max_calls})")
|
||||
|
||||
analyze_articles(
|
||||
force=force,
|
||||
dry_run=dry_run,
|
||||
use_claude=not no_claude,
|
||||
max_claude_calls=max_calls,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
15
dashboard.py
15
dashboard.py
@@ -28,12 +28,7 @@ from report import _c25_day_return, _unrealised_pnl, _realised_pnl, _total_fees,
|
||||
|
||||
CAPITAL = 10_000
|
||||
LOG_DIR = Path(os.getenv("LOG_DIR", str(Path(__file__).parent / "logs")))
|
||||
METRICS_FILE = Path(__file__).parent / "metrics.json"
|
||||
REFRESH = 60 # seconds
|
||||
|
||||
CAPITAL = 10_000
|
||||
LOG_DIR = Path(os.getenv("LOG_DIR", str(Path(__file__).parent / "logs")))
|
||||
METRICS_FILE = Path(__file__).parent / "metrics.json"
|
||||
METRICS_FILE = Path(os.getenv("DATA_DIR", str(Path(__file__).parent / "data"))) / "metrics.json"
|
||||
REFRESH = 60 # seconds
|
||||
|
||||
app = Flask(__name__)
|
||||
@@ -246,9 +241,9 @@ METRICS_TEMPLATE = """<!DOCTYPE html>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td>Model</td><td class="mono">claude-haiku-4-5</td><td>Anthropic</td></tr>
|
||||
<tr><td>Input price</td><td class="mono">$0.80 / MTok</td><td>${{ "%.6f"|format(0.80/1_000_000) }} per token</td></tr>
|
||||
<tr><td>Output price</td><td class="mono">$4.00 / MTok</td><td>${{ "%.6f"|format(4.00/1_000_000) }} per token</td></tr>
|
||||
<tr><td>Model</td><td class="mono">claude-3-haiku-20240307</td><td>Anthropic</td></tr>
|
||||
<tr><td>Input price</td><td class="mono">$0.25 / MTok</td><td>${{ "%.6f"|format(0.25/1_000_000) }} per token</td></tr>
|
||||
<tr><td>Output price</td><td class="mono">$1.25 / MTok</td><td>${{ "%.6f"|format(1.25/1_000_000) }} per token</td></tr>
|
||||
<tr><td>Total calls</td><td class="mono">{{ total_calls }}</td><td>articles sent to Claude</td></tr>
|
||||
<tr><td>Total input tokens</td><td class="mono">{{ "{:,}".format(total_input_tokens) }}</td><td>cost ${{ "%.5f"|format(cost_input) }}</td></tr>
|
||||
<tr><td>Total output tokens</td><td class="mono">{{ "{:,}".format(total_output_tokens) }}</td><td>cost ${{ "%.5f"|format(cost_output) }}</td></tr>
|
||||
@@ -298,7 +293,7 @@ window.addEventListener('resize', () => { barChart.resize(); donut.resize(); });
|
||||
</script>
|
||||
{% endif %}
|
||||
|
||||
<div class="footer">MoneyMaker · claude-haiku-4-5 · metrics updated on each analyze run</div>
|
||||
<div class="footer">MoneyMaker · claude-3-haiku-20240307 · metrics updated on each analyze run</div>
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user