summaryrefslogtreecommitdiff
path: root/scripts/stock_screener.py
diff options
context:
space:
mode:
authorTheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com>2026-04-02 10:13:10 +0900
committerTheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com>2026-04-02 10:13:10 +0900
commite9c791ae2b14884f8f0525da5fcaa1710ca1fc63 (patch)
tree752c219a95abe7bdbfbf0644711f7dede407aa7b /scripts/stock_screener.py
parent35120795147adf53de59b7f2a3c8aa14adec9a56 (diff)
refactor: complete US stock migration
- Data collector: Alpaca REST polling (replaces Binance WebSocket) - Order executor: Alpaca submit_order (replaces ccxt) - Claude stock screener: daily MOC candidate analysis - Remove ccxt/websockets dependencies - Default universe: AAPL, MSFT, GOOGL, AMZN, TSLA + 28 more - 399 tests passing, lint clean
Diffstat (limited to 'scripts/stock_screener.py')
-rwxr-xr-xscripts/stock_screener.py72
1 files changed, 52 insertions, 20 deletions
diff --git a/scripts/stock_screener.py b/scripts/stock_screener.py
index 387bfea..7a5c0ba 100755
--- a/scripts/stock_screener.py
+++ b/scripts/stock_screener.py
@@ -10,6 +10,7 @@ Usage:
Requires: ANTHROPIC_API_KEY environment variable
"""
+
import argparse
import asyncio
import json
@@ -51,15 +52,17 @@ async def get_market_data(alpaca: AlpacaClient, symbols: list[str]) -> list[dict
lows = [float(b["l"]) for b in bars]
range_pct = (max(highs) - min(lows)) / close * 100 if close > 0 else 0
- results.append({
- "symbol": symbol,
- "close": close,
- "change_pct": round(change_pct, 2),
- "volume": volume,
- "vol_ratio": round(vol_ratio, 2),
- "range_5d_pct": round(range_pct, 2),
- "is_bullish": close > float(latest["o"]), # Today bullish?
- })
+ results.append(
+ {
+ "symbol": symbol,
+ "close": close,
+ "change_pct": round(change_pct, 2),
+ "volume": volume,
+ "vol_ratio": round(vol_ratio, 2),
+ "range_5d_pct": round(range_pct, 2),
+ "is_bullish": close > float(latest["o"]), # Today bullish?
+ }
+ )
except Exception as exc:
print(f" Warning: Failed to fetch {symbol}: {exc}")
@@ -137,19 +140,45 @@ async def analyze_with_claude(prompt: str, api_key: str) -> list[dict]:
# Default universe of liquid US stocks
DEFAULT_UNIVERSE = [
# Tech
- "AAPL", "MSFT", "GOOGL", "AMZN", "META", "NVDA", "TSLA", "AMD", "INTC", "CRM",
+ "AAPL",
+ "MSFT",
+ "GOOGL",
+ "AMZN",
+ "META",
+ "NVDA",
+ "TSLA",
+ "AMD",
+ "INTC",
+ "CRM",
# Finance
- "JPM", "BAC", "GS", "MS", "V", "MA",
+ "JPM",
+ "BAC",
+ "GS",
+ "MS",
+ "V",
+ "MA",
# Healthcare
- "JNJ", "UNH", "PFE", "ABBV",
+ "JNJ",
+ "UNH",
+ "PFE",
+ "ABBV",
# Consumer
- "WMT", "KO", "PEP", "MCD", "NKE",
+ "WMT",
+ "KO",
+ "PEP",
+ "MCD",
+ "NKE",
# Energy
- "XOM", "CVX",
+ "XOM",
+ "CVX",
# Industrial
- "CAT", "BA", "GE",
+ "CAT",
+ "BA",
+ "GE",
# ETFs
- "SPY", "QQQ", "IWM",
+ "SPY",
+ "QQQ",
+ "IWM",
]
@@ -187,8 +216,7 @@ async def main_async(top_n: int = 5, universe: list[str] | None = None):
# Pre-filter obvious rejects
candidates = [
- s for s in market_data
- if s["is_bullish"] and s["vol_ratio"] >= 0.8 and s["change_pct"] > -2
+ s for s in market_data if s["is_bullish"] and s["vol_ratio"] >= 0.8 and s["change_pct"] > -2
]
print(f"Pre-filter: {len(candidates)} candidates (bullish, decent volume)\n")
@@ -211,7 +239,9 @@ async def main_async(top_n: int = 5, universe: list[str] | None = None):
# Find market data for this symbol
md = next((m for m in market_data if m["symbol"] == rec["symbol"]), None)
if md:
- print(f" Close: ${md['close']:.2f} | Change: {md['change_pct']:+.2f}% | Vol Ratio: {md['vol_ratio']:.1f}x")
+ print(
+ f" Close: ${md['close']:.2f} | Change: {md['change_pct']:+.2f}% | Vol Ratio: {md['vol_ratio']:.1f}x"
+ )
else:
print("Claude found no qualifying stocks today.")
else:
@@ -237,7 +267,9 @@ async def main_async(top_n: int = 5, universe: list[str] | None = None):
print("-" * 60)
for i, (s, score) in enumerate(scored[:top_n], 1):
print(f"#{i} {s['symbol']} (Score: {score})")
- print(f" Close: ${s['close']:.2f} | Change: {s['change_pct']:+.2f}% | Vol: {s['vol_ratio']:.1f}x")
+ print(
+ f" Close: ${s['close']:.2f} | Change: {s['change_pct']:+.2f}% | Vol: {s['vol_ratio']:.1f}x"
+ )
print("\n" + "=" * 60)