Market Watch: multiplayer GARP paper trading simulator
- Game engine with multiplayer support (create games, join, leaderboard) - GARP stock screener (S&P 500 + 400 MidCap, 900+ tickers) - Automated trading logic for AI player (Case) - Web portal at marketwatch.local:8889 with dark theme - Systemd timer for Mon-Fri market hours - Telegram alerts on trades and daily summary - Stock analysis deep dive data (BAC, CFG, FITB, INCY) - Expanded scan results (22 GARP candidates) - Craigslist account setup + credentials
This commit is contained in:
99
projects/market-watch/run_daily.py
Executable file
99
projects/market-watch/run_daily.py
Executable file
@ -0,0 +1,99 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Daily runner for Market Watch - scans, trades (as Case), snapshots, alerts."""
|
||||
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import requests
|
||||
from datetime import datetime
|
||||
|
||||
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
import game_engine
|
||||
from scanner import run_scan
|
||||
from trader import run_trading_logic
|
||||
|
||||
CREDS_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "..", ".credentials", "telegram-bot.env")
|
||||
CHAT_ID = "6443752046"
|
||||
|
||||
|
||||
def load_telegram_token():
|
||||
if os.path.exists(CREDS_FILE):
|
||||
with open(CREDS_FILE) as f:
|
||||
for line in f:
|
||||
if line.startswith("TELEGRAM_BOT_TOKEN="):
|
||||
return line.strip().split("=", 1)[1]
|
||||
return os.environ.get("TELEGRAM_BOT_TOKEN")
|
||||
|
||||
|
||||
def send_telegram(message, token):
|
||||
if not token:
|
||||
return
|
||||
try:
|
||||
url = f"https://api.telegram.org/bot{token}/sendMessage"
|
||||
requests.post(url, json={"chat_id": CHAT_ID, "text": message, "parse_mode": "HTML"}, timeout=10)
|
||||
except Exception as e:
|
||||
print(f"Telegram error: {e}")
|
||||
|
||||
|
||||
def main():
|
||||
print(f"📊 Market Watch Daily Run — {datetime.now().strftime('%Y-%m-%d %H:%M')}")
|
||||
|
||||
token = load_telegram_token()
|
||||
game_id = game_engine.ensure_default_game()
|
||||
game = game_engine.get_game(game_id)
|
||||
|
||||
# 1. Run GARP scan
|
||||
print("\n[1/3] Running GARP scan...")
|
||||
scan = run_scan()
|
||||
candidates = scan.get("candidates", [])
|
||||
print(f" Found {len(candidates)} candidates from {scan.get('total_scanned', 0)} stocks")
|
||||
|
||||
# 2. Run trading logic for Case
|
||||
print("\n[2/3] Running trading logic for Case...")
|
||||
result = run_trading_logic(game_id, "case", candidates)
|
||||
|
||||
# 3. Snapshots for all players
|
||||
print("\n[3/3] Taking snapshots...")
|
||||
for username in game["players"]:
|
||||
snap = game_engine.daily_snapshot(game_id, username)
|
||||
if snap:
|
||||
print(f" {username}: ${snap['total_value']:,.2f} ({snap['pnl_pct']:+.2f}%)")
|
||||
|
||||
# Telegram summary
|
||||
p = game_engine.get_portfolio(game_id, "case")
|
||||
pnl_emoji = "📈" if p["total_pnl"] >= 0 else "📉"
|
||||
|
||||
summary = f"📊 <b>Market Watch Daily</b>\n"
|
||||
summary += f"{pnl_emoji} Portfolio: ${p['total_value']:,.2f} ({p['pnl_pct']:+.2f}%)\n"
|
||||
summary += f"💰 Cash: ${p['cash']:,.2f} | Positions: {p['num_positions']}\n"
|
||||
|
||||
num_trades = len(result.get("sells", [])) + len(result.get("buys", []))
|
||||
if num_trades:
|
||||
summary += f"\n<b>{num_trades} trades executed</b>\n"
|
||||
for s in result.get("sells", []):
|
||||
summary += f"🔴 SELL {s['ticker']} — {s['reason'][:50]}\n"
|
||||
for b in result.get("buys", []):
|
||||
summary += f"🟢 BUY {b['ticker']} — {b['reason'][:50]}\n"
|
||||
else:
|
||||
summary += "\nNo trades today."
|
||||
|
||||
if candidates:
|
||||
top5 = ", ".join(c["ticker"] for c in candidates[:5])
|
||||
summary += f"\n🔍 Top picks: {top5}"
|
||||
|
||||
# Leaderboard
|
||||
board = game_engine.get_leaderboard(game_id)
|
||||
if len(board) > 1:
|
||||
summary += "\n\n<b>Leaderboard:</b>\n"
|
||||
medals = ["🥇", "🥈", "🥉"]
|
||||
for i, entry in enumerate(board[:5]):
|
||||
medal = medals[i] if i < 3 else f"#{i+1}"
|
||||
summary += f"{medal} {entry['username']}: {entry['pnl_pct']:+.2f}%\n"
|
||||
|
||||
send_telegram(summary, token)
|
||||
print("\n✅ Daily run complete")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user