═══════════════════════════════════════════════════════════════════════════════ KALSHIBOT — COMPLETE PROJECT HANDOFF DOCUMENT Last updated: April 6 2026 — 3 bots running overnight For: Ennis (Windows 11, C:\kalshibot) NEVER delete anything from this file. Only add new sections to the bottom. Purpose: Paste entire file into a new Claude chat to resume with full context. ═══════════════════════════════════════════════════════════════════════════════ Continue my Kalshibot project. Check memory first, then read this entire file. ──────────────────────────────────────────────────────────────────────────────── SECTION 1: WHAT THIS PROJECT IS ──────────────────────────────────────────────────────────────────────────────── A Python trading bot paper-trading Kalshi prediction markets — KXBTC15M series: "Will BTC be above $X in the next 15 minutes?" HOW KALSHI MARKETS WORK: - Markets open every 15 minutes, 24/7, no breaks - Each market has YES/NO contracts priced 1-99 cents - Buy YES at 72c, BTC stays above floor at expiration → win $1.00 (profit 28c) - Buy NO at 28c, BTC drops below floor → win $1.00 (profit 72c) - Can sell early when price moves in your favor before expiration - Max payout always $1.00. 3-4 overlapping windows open at any time. - Bot scans ALL open windows and picks the highest scoring one to trade. - Floor (strike) is set by Kalshi at market open based on current BTC price. FINANCIAL GOALS: - Paper trade first — prove 60%+ WR over 200+ trades before going live - Go live with $250 real deposit, target $20/day → $50-500/day long term - Bet sizes scale UP as win rate and balance prove themselves - Small consistent wins preferred. Conservative real-money risk management. ──────────────────────────────────────────────────────────────────────────────── SECTION 2: SYSTEM / ENVIRONMENT ──────────────────────────────────────────────────────────────────────────────── OS: Windows 11, user: ennis, folder: C:\kalshibot\, Python 3.14 CRITICAL: Always CMD. Never PowerShell for running Python — it freezes scripts. Kalshi API: live credentials in .env + kalshi_private_key.txt (never commit these) PYTHON PROCESS BEHAVIOR ON WINDOWS: When you type "python script.py" in PowerShell or CMD, Windows launches TWO python.exe processes — the Windows Store stub (WindowsApps path) which spawns the real Python 3.14 (pythoncore path). This means 3 bots = 6 python.exe processes. This is NORMAL. Do not kill the stub processes. Check with: Get-WmiObject Win32_Process -Filter "Name='python.exe'" | Where-Object {$_.CommandLine -like "*paper_trade*"} | Select-Object ProcessId, ParentProcessId, CommandLine GIT / GITHUB WARNING: Repo: https://github.com/Thrival/Kalshibot.git Branches: main (prod), test (test bot), highroller (high roller bot) CRITICAL: git branch switching (git checkout branchname) DELETES files from disk that belong to other branches. Always use FileSystem copy to create new bot files. To restore a deleted file: git checkout branchname -- filename.py Always commit after every meaningful change. Version: v1.1, v1.2, v2.0 etc. Include WR + what changed in every commit message. ──────────────────────────────────────────────────────────────────────────────── SECTION 3: ALL FILES AND WHAT THEY DO ──────────────────────────────────────────────────────────────────────────────── BOTS (all currently running, all $250 balance): paper_trade.py MAIN BOT. MOM required on all trades. SCORE_MEDIUM=15. EXP only fires in final 5 min of window. paper_trade_test.py TEST BOT. SCORE_MEDIUM=35. EXP-alone allowed (no MOM). MIN_ENTRY_PRICE=0.50. Testing: EXP at high confidence. paper_trade_highroller.py HIGH ROLLER. Identical strategy to main. 3x bet sizes. SUPPORT: btc_scanner.py Live money bot. Same infrastructure as paper_trade.py. DO NOT RUN until main bot proves 60%+ WR. When ready, sync ALL parameters from paper_trade.py before launching. dashboard.html 2-tab Chrome UI served at http://localhost:8765 Reads bot_state.json written every scan cycle by main bot. Main bot only — test/highroller don't write bot_state.json. analyzer.py Learning engine. Run: python analyzer.py Reads trade_analytics.json (main bot ONLY). Does NOT read test or highroller files. Outputs auto_params.json with tuning suggestions. Hour blocking output PERMANENTLY DISABLED in analyzer. new_chat.txt This file. Never delete, only append. HANDOFF_PROMPT.txt Short one-paragraph prompt version for quick new chats. DATA FILES (NEVER delete any of these): trade_analytics.json Main bot — permanent learning record, appended forever trade_analytics_test.json Test bot — separate, never mix with main trade_analytics_highroller.json High roller — separate market_snapshots.json BTC + Kalshi odds every 10s (main bot) market_snapshots_test.json Test bot snapshots market_snapshots_highroller.json High roller snapshots paper_log.json Main bot current session (resets on restart, analytics preserved) paper_log_test.json Test current session paper_log_highroller.json High roller current session data/session_history.json Every session summary ever (main bot) data/session_history_test.json Test bot sessions data/session_history_highroller.json High roller sessions data/archive/ Auto-archived files at 5000/10000 record thresholds auto_params.json Learning engine output loaded by bots on startup bot_state.json Real-time bridge: main bot → dashboard (written every 10s) BACKUPS: C:\kalshibot\backups\ paper_trade_pre_bugfix.py early backup paper_trade_pre_analysis_fix.py before data-driven changes paper_trade_pre_exp_fix.py before EXP timing + score threshold fix paper_trade_pre_explag_block.py before EXP+LAG block paper_trade_pre_mom_required.py before MOM-required on all trades (most recent) ──────────────────────────────────────────────────────────────────────────────── SECTION 4: COMPLETE STRATEGY HISTORY — EVERY PHASE, WHAT WORKED, WHAT DIDN'T ──────────────────────────────────────────────────────────────────────────────── ═══ PHASE 1 — PURE MOMENTUM (FAILED, ~39% WR) ═══ First strategy: detect BTC price momentum over 2 minutes. If BTC up 0.05%+ → buy YES. If BTC down 0.05%+ → buy NO. Result: 135 trades, 39% WR, lost $5.50. WHY IT FAILED: Kalshi market makers reprice contracts WITHIN SECONDS of BTC moving. By the time our bot detected momentum and placed a trade, the market had already adjusted. We were consistently buying after the edge was gone. The momentum was real — but we were always too late to capture it. THINGS TRIED IN PHASE 1 THAT WERE REMOVED: 1. BALANCED signal — trade when YES price is 30-70c (theoretically fair value). Result: fired constantly on every scan, pure noise, no edge. Removed entirely. 2. Fixed bet tiers (WEAK/BASE/MEDIUM/STRONG with fixed dollar amounts). Problem: didn't scale with balance or signal confidence. Replaced by Kelly-inspired dynamic bet sizing. 3. Per-window trade lock — once we entered a window, locked it out. Problem: prevented re-entries even when a new valid signal appeared. Removed at user request. Bot can re-enter same window unlimited times. 4. Volume check to skip markets — skipped markets with volume=0. Problem: brand new markets always start at volume=0 but have valid prices. Replaced with yes_ask > 0 check (if price exists, market is valid). ═══ PHASE 2 — PARAMETER TUNING (NOT ENOUGH ALONE) ═══ Kept the momentum signal but tuned parameters aggressively: - Momentum threshold raised 0.05% → 0.1% (filter out weak signals) - Max bet size reduced $5 → $2 (reduce losses while testing) - Added fast position monitor thread (checks exits every 1s not 10s) - Added dedicated Kalshi background poll thread (market data every 3s) - Added hot-path trigger: if BTC moves 0.12%+ it fires threading.Event waking the main loop instantly instead of waiting up to 5 seconds. This gave us a chance to beat the market maker's repricing lag. - Added 5 simultaneous price feeds as daemon threads: Binance.US WebSocket (primary, real-time) Binance.US REST (fallback, every 8s) Coinbase REST (every 5s) Kraken REST (every 8s) OKX REST (every 4s) KEY LESSON FROM PRICE FEEDS: All 5 feeds MUST run simultaneously as daemon threads from the start. Early version treated REST feeds as fallbacks — only started them if WebSocket failed. This caused a permanent "warming up" bug where only Binance WebSocket was writing to price_history, and if it was slow to connect, the bot would stay in warmup state forever. FIX: All feeds start immediately in run(), regardless of WebSocket state. Result of Phase 2 alone: marginal improvement, still losing overall. ═══ PHASE 3 — STRATEGY PIVOT: EXP + LAG + MOM SCORING (CURRENT) ═══ Completely rebuilt signal system. Three independent signals scored 0-100pts. Total score determines whether to trade and how much to bet. SIGNAL 1 — EXPIRATION VALUE (EXP, 0-50 pts) — THE CORE MATHEMATICAL EDGE: Insight: As a window approaches expiration, the probability of YES winning becomes increasingly predictable from BTC's distance to the floor price. If BTC is $500 above the floor with only 3 minutes left, the chance of BTC dropping below the floor is mathematically tiny — maybe 2-3%. If Kalshi is pricing YES at 82c (82%), that's a 15% mispricing — pure arbitrage opportunity. Formula: expected_range = BTC_price * BTC_VOL_PER_MIN * sqrt(mins_left) z_score = (BTC_price - floor) / expected_range probability = normal_CDF(z_score) mispricing = probability - kalshi_yes_price (if buying YES) or kalshi_no_price - (1 - probability) (if buying NO) exp_score = int(mispricing * 500) (multiplier=500, so 2% → 10pts) Parameters: MIN_MISPRICING = 0.015 (need at least 1.5% mispricing to score any points) EXP multiplier = 500 (raised from 220 — original was too low, 3.4% only scored 7) BTC_VOL_PER_MIN = 0.00040 (BTC moves ~0.04% per minute on average) Main bot: EXP only fires when secs_left < 300 (final 5 minutes) Reason for 5-min restriction: EXP formula is unreliable at long horizons because volatility is harder to estimate accurately 10-15 min out. Test confirms: EXP at all horizons = 24% WR. Final-5-min only = better. SIGNAL 2 — LAG DETECTION (LAG, 0-30 pts): Insight: Kalshi market makers sometimes lag BTC by 5-45 seconds after sharp BTC moves. If BTC just jumped 0.1% but the Kalshi contract hasn't repriced yet, we can enter before the market catches up. Formula: btc_move = (current_btc - btc_45s_ago) / btc_45s_ago expected_yes_move = btc_move * 1.5 (rough sensitivity estimate) actual_yes_move = current_yes_ask - yes_ask_45s_ago lag = expected_yes_move - actual_yes_move if lag > 0.03: score = int(min(30, lag * 250)) Parameters: LAG_WINDOW_SECS = 45 LAG_MIN_BTC_MOVE = 0.0006 (0.06% minimum BTC move to check for lag) Requires Binance WS connected — if only Coinbase/Kraken: LAG always 0 SIGNAL 3 — MOMENTUM CONFIRMATION (MOM, 0-20 pts): The original Phase 1 momentum signal, kept as a confirming signal. strength = abs(momentum_pct) / MOMENTUM_THRESHOLD mom_score = int(min(20, strength * 6)) Direction must match trade direction — opposing momentum is hard-blocked. ──────────────────────────────────────────────────────────────────────────────── SECTION 5: WHAT WORKED AND WHAT FAILED — COMPLETE SIGNAL WIN RATE DATA ──────────────────────────────────────────────────────────────────────────────── As of April 6 ~00:10 (88 exits on main bot, 50 on test, 2 on highroller): PROVEN WINNERS — keep, never remove: EXP+MOM: 5W/1L 83% WR +$2.38 BEST SIGNAL. The core edge. EXP+LAG+MOM: 1W/0L 100% WR +$1.70 All 3 confirming = perfect. Small sample but consistent. PROVEN LOSERS — conclusive data, do not re-enable: EXP alone: 13W/24L 35% WR -$3.81 37 trades = CONCLUSIVE. Tested at ALL score thresholds. Test bot SCORE>=35: 19% WR (42 trades). EXP without MOM is dead. Never again. EXP+LAG no MOM: 1W/4L 20% WR -$6.28 BLOCKED. Catastrophic losses. LAG+MOM: 2W/4L 33% WR -$0.70 Worse than expected. Watching. LAG alone: 5W/9L 36% WR -$1.11 Losing, watching. MOM alone: 7W/12L 37% WR -$3.79 Collapsed from 60% early WR. Was our best signal initially. May be market conditions, watching. SCORE/TIER BREAKDOWN: HIGH tier (score 28+): 41% WR — dragged down by EXP-alone at high scores MEDIUM tier (score 15-27): 52% WR — actually approaching our target ENTRY PRICE BREAKDOWN: <0.35 (now blocked): 20% WR — disastrous, cheap contracts buy 64 units 0.35-0.50: 33% WR — weak 0.50-0.65: 55% WR — BEST BUCKET, consistently profitable 0.65-0.80: 42% WR — moderate 0.80+: 33% WR — expensive contracts, limited upside TIME LEFT AT ENTRY: 700-900s (just opened): 27% WR — terrible, market still settling 500-700s: 42% WR — weak 300-500s: 33% WR — weak 180-300s (final 5 min): 58% WR — approaching target 0-180s (final 3 min): 50% WR — decent NOTE: User decided NOT to restrict to final 5 min for LAG/MOM signals. Trade the full 15 minute window. Data noted for context only. WHAT WAS EXPLICITLY TESTED AND REJECTED: 1. EXP with no time restriction (test bot v1 overnight): Result: 24% WR across 29 trades. WORSE than 5-min restriction. Decision: keep EXP restricted to final 5 min in main bot. 2. EXP-alone at high confidence SCORE_MEDIUM=35 (test bot v2, current): Result so far: 19% WR across 42 trades. Confirms: EXP-alone fails at every score threshold, not just low ones. 3. SCORE_MEDIUM=10 (test bot, early overnight): Generated lots of trades but terrible quality. 20-25% WR across all signals. Confirmed: lower threshold = more noise, not more opportunity. 4. Hour blocking via auto_params: The analyzer would identify "good hours" (60%+ WR) and "avoid hours" (40%-) and write them to auto_params.json which bots would load on startup. Problem: With only 84 total trades spread across ~6 hours, each hour bucket had maybe 10-20 trades. Far too small to be statistically meaningful. One bad hour could be pure variance, not a real pattern. Decision: PERMANENTLY DISABLED in all files. Needs 1000+ trades per hour bucket (weeks of data) before hours have any meaning whatsoever. Removed from: paper_trade.py, paper_trade_test.py, paper_trade_highroller.py, btc_scanner.py, analyzer.py. Hour data still collected but never blocks trades. DECISIONS MADE — DO NOT REVERSE WITHOUT EXPLICITLY ASKING: ✅ Trade full 15 minute window (LAG/MOM not restricted to final minutes) ✅ All hours tradeable — no time-of-day blocking, permanently ✅ $250 balance on all bots ✅ MOM required on every trade in main bot (applied April 6) ✅ No parlays ever under any circumstances ✅ Session stop loss disabled for paper (bots can go to $0 — it's paper money) ✅ Trailing stop disabled for paper (want clean behavior data) ✅ Analyzer reads main bot only — test/highroller analyzed manually ✅ EXP+LAG block is permanent — 0-20% WR proven, never re-enable ✅ MIN_ENTRY_PRICE=0.35 — cheap contracts at 0.12-0.25 had 20% WR ──────────────────────────────────────────────────────────────────────────────── SECTION 6: ALL CURRENT PARAMETERS — EVERY SETTING IN EVERY BOT ──────────────────────────────────────────────────────────────────────────────── MAIN BOT (paper_trade.py) — v1.4: STARTING_BALANCE = 250.00 PROFIT_TARGET = 0.40 (40% gain target per trade) EXIT_CAP = 0.92 (target never above 0.92, exits fast) STOP_LOSS = 0.25 (25% loss = exit) TRAILING_STOP_PCT = 0.20 (DISABLED for paper — data collection) MAX_ENTRY_PRICE = 0.82 (never buy contract above 82c) MIN_ENTRY_PRICE = 0.35 (never buy below 35c — cheap = losers) MAX_POSITIONS = 5 (max 5 simultaneous open positions) MAX_CONTRACTS_PER_TRADE = 10 (hard cap — prevents runaway counts) SCAN_INTERVAL = 5s (main loop checks every 5s) ENTRY_COOLDOWN = 30s (30s minimum between entries) MIN_SECS_LEFT = 30s (won't enter if <30s left in window) FAST_MONITOR_INTERVAL = 1s (position exit check every 1s) KALSHI_POLL_INTERVAL = 3s (market data refresh every 3s) HOT_PATH_BTC_MOVE = 0.0012 (0.12% BTC move triggers instant rescan) MOMENTUM_SECONDS = 120 (2-minute momentum window) MOMENTUM_THRESHOLD = 0.0010 (0.10% minimum momentum to score) SCORE_MEDIUM = 15 (minimum score to place any trade) SCORE_HIGH = 28 (score >= 28 = HIGH tier) MIN_MISPRICING = 0.015 (1.5% minimum EXP mispricing) EXP multiplier = 500 (2% mispricing = 10pts) LAG_WINDOW_SECS = 45 LAG_MIN_BTC_MOVE = 0.0006 BTC_VOL_PER_MIN = 0.00040 (fallback volatility estimate) EXP restriction = secs_left < 300 (final 5 min only) MOM requirement = mom_score > 0 on EVERY trade (hard block) Hour blocking = permanently disabled Session stop loss = disabled for paper KELLY BET SIZING (main bot): score 15-44 → 1% of balance score 45-54 → 2% score 55-64 → 3% score 65-74 → 5% score 75-84 → 8% score 85-89 → 12% score 90+ → 15% (hard cap) Floor: $0.50 minimum bet. Cap: 15% of balance max. At $250: score-65 = $12.50 bet. Score-90 = $37.50 bet. HIGH ROLLER BOT (paper_trade_highroller.py): Everything identical to main bot EXCEPT bet sizing is 3x: score 15-44 → 3% score 45-54 → 6% score 55-64 → 9% score 65-74 → 15% score 75-84 → 22% score 85-89 → 30% score 90+ → 40% (hard cap) Floor: $1.00 minimum bet. Cap: 40% of balance max. At $250: score-65 = $37.50 bet. Score-90 = $100 bet. Analytics: trade_analytics_highroller.json TEST BOT (paper_trade_test.py) — current experiment: STARTING_BALANCE = 250.00 SCORE_MEDIUM = 35 (much higher threshold — high confidence only) MIN_ENTRY_PRICE = 0.50 (raised — best price bucket was 0.50-0.65) MOM requirement = REMOVED (testing EXP-alone at high confidence) EXP restriction = REMOVED (fires at all time horizons) EXP+LAG block = KEPT (still active) Opposing MOM block = KEPT (still active) Analytics: trade_analytics_test.json Question being tested: Does EXP-alone work at score >= 35? Early result: 19% WR (42 trades) — likely NO. SELF-LEARNING THRESHOLDS (analyzer.py): AUTO_MIN_BUCKET_TRADES = 20 (need 20+ trades in a bucket to act on it) AUTO_MIN_WIN_RATE = 0.60 (60%+ to call something "good") AUTO_MAX_WIN_RATE = 0.40 (40%- to call something "avoid") AUTO_RETUNE_EVERY = 30 (re-run analysis every 30 completed trades) ARCHIVE_ANALYTICS_AT = 5000 (archive trade_analytics.json at 5000 records) ARCHIVE_SNAPSHOTS_AT = 10000 ──────────────────────────────────────────────────────────────────────────────── SECTION 7: COMPLETE ARCHITECTURE — HOW THE BOT WORKS INTERNALLY ──────────────────────────────────────────────────────────────────────────────── THREAD ARCHITECTURE (all daemon threads started in run()): main loop — Entry decisions every 5s OR instantly via hot path fast_monitor_loop — Checks ALL open positions for exit every 1s poll_kalshi_market — Fetches ALL open KXBTC15M markets, caches every 3s start_dashboard_server — Serves C:\kalshibot\ at localhost:8765 (HTTP) binance_ws — Real-time BTC price (Binance.US only — .com removed) poll_binance_rest — REST fallback every 8s (Binance.US) poll_coinbase — Coinbase REST every 5s poll_kraken — Kraken REST every 8s poll_okx — OKX REST every 4s ALL PRICE FEEDS MUST START AS DAEMON THREADS SIMULTANEOUSLY. Never treat REST feeds as fallbacks. Early bug: treating REST as fallback caused permanent "warming up" state. Only Binance WS was writing to price_history. Fix: all 5 start immediately in run() regardless of WS state. MAIN LOOP CYCLE (every 5s or instant via hot_path_event): 1. Get best BTC price from all feeds (freshness check: reject >30s old) 2. Calculate 2-minute momentum and direction (UP/DOWN/FLAT) 3. Read all_markets_cache (NO blocking API call — just reads cached data) 4. Score EVERY open market → pick highest-scoring one 5. Print status line (shows score, EXP/LAG/MOM breakdown, balance, positions) 6. Save bot_state.json (dashboard reads this every few seconds) 7. Log market snapshot to market_snapshots.json 8. Auto-analyze if 30 more trades completed since last analysis 9. Check can_trade conditions 10. Enter trade if all conditions met CAN_TRADE CONDITIONS (ALL must be true to place a trade): - Not in warmup period (WARMUP_TICKS = 4 cycles) - Session not halted (session stop loss — disabled for paper) - Market is not None (valid market found) - tier is not None (score >= SCORE_MEDIUM) - trade_dir is not None and not "FLAT" - open positions < MAX_POSITIONS (5) - time since last entry > ENTRY_COOLDOWN (30s) - secs_left > MIN_SECS_LEFT (30s) - valid entry price (yes_ask > 0 and no_ask > 0) - balance >= $0.50 - hour_blocked = False (always False — hour blocking permanently disabled) - MOM not opposing trade direction (hard block in get_confidence_score) - mom_score > 0 (main bot only — MOM required block) SCORING ENGINE (get_confidence_score): 1. score_expiration_value() → exp_score, exp_dir 2. score_lag_detection() → lag_score, lag_dir 3. Resolve trade_dir: exp_dir OR lag_dir OR momentum_dir 4. Check opposing momentum → if opposing: return 0 (hard block) 5. Check EXP+LAG no MOM → if exp>0 AND lag>0 AND mom=0: return 0 (block) 6. Check MOM required → if mom_score==0: return 0 (main bot only) 7. Calculate total = exp_score + lag_score + mom_score 8. Assign tier: HIGH (>=28) or MEDIUM (>=15) or None (below threshold) DATA PRESERVATION ON RESTART (preserve_and_archive() runs FIRST): 1. Save session summary → data/session_history.json 2. Archive files if over threshold → data/archive/ 3. THEN reset paper_log.json to $250 and clear balance Analytics (trade_analytics.json) NEVER wiped — appended forever. PRIVATE KEY CACHING: Loaded from disk ONCE at startup, cached in _private_key_cache. Original bug: loaded from disk on EVERY API call including fast_monitor. With positions being checked every 1s, this caused 1 disk read per second. Fix: load once in get_private_key(), cache forever for session. HOT PATH TRIGGER: Binance WS on_message checks if BTC moved 0.12%+ since last hot path check. If yes: sets hot_path_event threading.Event. Main loop waits on this event with 5s timeout. Result: instant rescan when BTC makes a sharp move, without busy-waiting. Bug fixed: OKX was updating _last_hot_btc after every poll, spamming events. ──────────────────────────────────────────────────────────────────────────────── SECTION 8: COMPLETE BUG FIX HISTORY — EVERY BUG FOUND AND HOW IT WAS FIXED ──────────────────────────────────────────────────────────────────────────────── 1. DASHBOARD COMPLETELY DEAD Symptom: Dashboard showed nothing, no data, completely blank. Cause: Duplicate "const bal" JavaScript variable declared twice in dashboard.html. Browser's JS engine crashed silently on load — nothing ran. Fix: Removed duplicate declaration. 2. FLAT DIRECTION TRIGGERING NO TRADES Symptom: Bot was placing NO trades when market was "flat." Cause: direction="FLAT" was being passed to paper_enter as trade_dir. paper_enter defaulted to NO side when direction wasn't "UP". Fix: Added explicit check — FLAT direction returns 0 from scoring, no trade. 3. IMPOSSIBLE PROFIT TARGETS Symptom: Target prices above $1.00, which Kalshi can never pay. Cause: entry_price * (1 + PROFIT_TARGET) with PROFIT_TARGET=0.40 at entry price 0.82 = 0.82 * 1.40 = $1.148. Kalshi max is $1.00. Fix: exit_cap = min(calculated_target, 0.92). Hard ceiling at 92c. 4. EXP SCORE MULTIPLIER TOO LOW Symptom: 3.4% mispricing only scored 7 points (barely above SCORE_MEDIUM). Cause: Original multiplier was 220. 3.4% * 220 = 7.48 ≈ 7. Fix: Raised multiplier to 500. Now 3.4% → 17 points (safely MEDIUM). 5. ZERO VOLUME BLOCKING NEW MARKETS Symptom: Brand new windows (just opened) were being skipped entirely. Cause: Bot checked volume > 0 to validate markets. New markets start at 0. Fix: Replaced volume check with yes_ask > 0 and no_ask > 0. If valid prices exist, the market is tradeable regardless of volume. 6. PER-WINDOW TRADE LOCK Behavior: Once we traded a window ticker, it was added to traded_tickers set and skipped on future scans. Issue: Prevented re-entries when a new valid signal appeared later. Removed at user request. Bot can enter same window multiple times. 7. GLOBAL SCOPE CRASH IN AUTO_ANALYZE Symptom: Bot crashed when auto_analyze() tried to update good_hours/avoid_hours. Cause: Python treated avoid_hours and good_hours as local variables inside auto_analyze() because of assignment (=). Not declared global. Fix: Added "global avoid_hours, good_hours" to auto_analyze(). 8. BINANCE WS RECURSIVE RECONNECT Symptom: After Binance WS disconnected, it would reconnect but create increasingly deep call stacks. Eventually would stack overflow. Cause: on_close callback called binance_ws() directly (recursive). Fix: Removed recursive call. Outer while True loop in binance_ws() handles reconnect automatically when inner run_forever() returns. Now tries Binance.US first, Binance.com as fallback (later .com removed). 9. HTTP DASHBOARD SERVER MISSING Symptom: Dashboard at localhost:8765 returned "connection refused." Cause: start_dashboard_server() thread was accidentally dropped during a code refactor. Thread existed but was never started. Fix: Added back as daemon thread in run() startup sequence. Dashboard serves entire C:\kalshibot\ folder — dashboard.html can fetch bot_state.json which bot writes every scan cycle. 10. TRADED_TICKERS GLOBAL CRASH Symptom: Bot crashed immediately on startup with UnboundLocalError. Cause: traded_tickers += set() inside run() — Python saw this as local variable assignment, not modification of global set. Fix: Added "global traded_tickers" declaration in run(). Later: traded_tickers was dead code entirely (see #18). 11. UNDEFINED 'TIER' IN PAPER_ENTER — CRASH ON EVERY TRADE Symptom: Every single trade attempt crashed the bot immediately. Cause: print() and return statements in paper_enter referenced variable 'tier' which doesn't exist in paper_enter scope. It's 'signal_type' inside that function. Fix: Replaced all 'tier' references in paper_enter with 'signal_type'. This was the most critical bug — the bot couldn't trade at all. 12. PRIVATE KEY LOADED FROM DISK ON EVERY API CALL Symptom: Slow API calls, unnecessary disk I/O. Cause: get_headers() called load_private_key() every time, including the fast position monitor which runs every 1 second. Fix: _private_key_cache global, loaded once at first call, reused forever. 13. BINANCE WS DOUBLE RECONNECT LOOP Symptom: After disconnect, Binance WS would connect twice simultaneously. Cause: on_close called binance_ws() AND the outer while loop also restarted. Fix: Removed the recursive call from on_close entirely. Loop handles it. 14. OKX HOT PATH SPAMMING MAIN LOOP Symptom: Main loop was being triggered almost every second on OKX polls. Cause: OKX poll function was calling hot_path_event.set() but never updating _last_hot_btc. Every poll looked like a 0.12%+ BTC move. Fix: Added _last_hot_btc update after OKX price check. 15. SAVE_STATE RECALCULATING CONFIDENCE SCORE Symptom: Minor performance issue, redundant computation. Cause: save_state() was re-running get_confidence_score() even though the score was already computed in the main loop. Fix: Pass pre-computed score into save_state() directly. 16. STALE BINANCE PRICE SLIPPING THROUGH Symptom: Bot occasionally used a BTC price that was 60+ seconds old. Cause: get_best_price() didn't check freshness of Binance price. If WebSocket stalled, stale Binance price was still used as primary. Fix: Added 30-second freshness check. Reject Binance price if >30s old, fall through to Coinbase/Kraken instead. 17. DEAD LEGACY WRAPPERS REMOVED get_signal(), get_bet_size(), paper_monitor() — old functions from Phase 1 that were no longer called anywhere. Removed to clean up codebase. 18. TRADED_TICKERS DEAD CODE REMOVED traded_tickers set was maintained (added to, intersected with) but never actually used to block anything after the per-window lock was removed (#6). Removed entirely. 19. OPPOSING MOMENTUM HARD BLOCK Original behavior: mom_score was capped with max(0, mom_score) when direction opposed trade_dir. This zeroed the MOM component but still allowed the trade to fire on EXP or LAG points alone. Problem: EXP-alone was already losing badly. Letting EXP trade INTO active opposing BTC momentum was making losses worse. Fix: If momentum direction actively opposes trade direction, return 0 from get_confidence_score entirely. Trade is skipped completely. 20. MIN_ENTRY_PRICE RAISED 0.12 → 0.35 Data showed: contracts priced 0.12-0.25 had 20% WR. Root cause: At 12c a contract, bet sizing bought 64+ contracts at once (bet_amount / contract_price). 64 contracts * 12c = $7.68 bet — huge. If that trade lost, the loss was amplified 64x vs a normal 5-10 contract trade. Fix: MIN_ENTRY_PRICE = 0.35. Won't enter any contract below 35c. 21. MAX_CONTRACTS_PER_TRADE = 10 Added as hard cap to prevent #20 style disasters. Even if entry price is 35c, max 10 contracts = $3.50 max bet at that price. Combined with MIN_ENTRY_PRICE, prevents runaway contract counts. 22. EXP RESTRICTED TO FINAL 5 MINUTES Data: EXP at 5-14 minutes remaining had 30% WR. Reason: The volatility formula assumes BTC moves randomly. At 10-14 min out, there's enough time for BTC to make multiple swings. The formula was overconfident — treating 10 minutes of remaining time as "almost certain." Fix: EXP only fires when secs_left < 300 (final 5 min of window). Test bot v1 confirmed: removing this restriction → 24% WR. Keep it. 23. SCORE_MEDIUM RAISED 7 → 15 Data: Trades with score 7-14 were consistently losing across all signal types. The bar was too low — too many weak signals getting through. Fix: SCORE_MEDIUM = 15. Anything below 15 is not a trade. 24. EXIT CAP LOWERED 0.97 → 0.92 Original: target up to 97c. Problem: near-expiry contracts rarely hit 97c. Positions were staying open too long waiting for an unreachable target. This tied up position slots unnecessarily. Fix: Cap at 0.92. Exits faster, frees position slots, minimal profit loss. 25. MAX_POSITIONS RAISED 3 → 5 Original cap was 3 simultaneous positions. With 3-4 overlapping windows open, sometimes all 3 slots were filled with one window's trades. Fix: Raised to 5 — allows more simultaneous positions across different windows. 26. MIN_SECS_LEFT LOWERED 90 → 30 Original: wouldn't enter a market with less than 90 seconds remaining. Data: Final minute of a window can have good EXP signals (very near expiry). Fix: 30 seconds minimum. Bot can now trade in the final minute. 27. TRAILING STOP DISABLED FOR PAPER Trailing stop would halt the session if balance dropped too far from peak. For paper trading: want to see full bot behavior without artificial halting. Data collection is the priority over balance protection. Fix: check_session_stop_loss() returns False always for paper. Re-enable for live bot (btc_scanner.py) before first real trade. 28. BINANCE.COM REMOVED Running as US user, Binance.com was consistently failing or blocked. Binance.US works fine. No need for .com fallback. Fix: Removed all Binance.com URLs. Binance.US only. 29. EXP+LAG BLOCK (no MOM = skip) Data: EXP+LAG with MOM=0 had 0-20% WR across 5 trades, -$6-8 losses. When both EXP and LAG fire but momentum is flat, it usually means BTC isn't actually moving anywhere. The "mispricing" doesn't resolve. Fix: In get_confidence_score() — if exp>0 AND lag>0 AND mom_score==0: return 0. Trade skipped entirely. 30. BOTH BOTS RAISED TO $250 Main bot was $100. User requested $250 on all bots. Consistent across all three bots now. 31. HOUR BLOCKING PERMANENTLY DISABLED See Section 5 for full explanation. Removed from all 4 files. 32. MOM REQUIRED ON ALL TRADES (main bot) Data: After 37 EXP-alone trades at 30-35% WR, pattern is conclusive. After 14 LAG-alone trades at 36% WR, also losing. Only signals with MOM confirming are profitable. Fix: After calculating mom_score, if mom_score == 0: return 0. Skip. Applied to main bot and highroller. Test bot intentionally excludes this. 33. HIGH ROLLER BOT CREATED Same strategy as main bot, 3x bet sizes, separate analytics file. Purpose: See what the strategy looks like at higher risk/reward. If main bot proves 60%+ WR, highroller shows potential live earnings. 34. TEST BOT REPURPOSED v2 First version tested EXP at all time horizons → 24% WR, failed. Current version tests EXP-alone at high confidence (SCORE_MEDIUM=35). Early result: 19% WR → likely confirms EXP-alone fails everywhere. ──────────────────────────────────────────────────────────────────────────────── SECTION 9: FUTURE IDEAS — DISCUSSED BUT NOT YET BUILT ──────────────────────────────────────────────────────────────────────────────── These were discussed and noted for future consideration. None are started. ALWAYS ask user before starting any new experiment or feature. STRATEGY IDEAS: Option A — EXP+MOM only, lower threshold: Only trade when BOTH EXP and MOM fire. Lower EXP MIN_MISPRICING so EXP fires more often at valid times. Goal: more EXP+MOM trades (83% WR). Trade-off: fewer total trades, higher quality. Option B — Pure expiration, final 2 minutes only: In the last 2 minutes, if BTC is far from the floor, outcome is near-certain. Trade only these highest-conviction setups with larger bets. Expected WR: very high (90%+). Expected frequency: low (5-10/hour). Most "pure" mathematical edge in the system. Option C — Price reversion / fade spikes: When Kalshi YES price spikes 20c+ in 30 seconds but BTC hasn't moved, the market overreacted. Fade it — buy the other side. Completely different signal type. Doesn't depend on predicting BTC direction. Requires tracking Kalshi price history more carefully. Option D — KXBTCD daily markets: Same scoring engine applied to daily BTC level markets. Longer windows = more time for signals to develop. Same codebase, different series_ticker. Option E — Near-zero accumulation: When EXP says a 2-8c NO contract is underpriced, buy many of them. If market prices NO at 3c but true probability says 8c, that's huge edge. Risk: cheap contracts fail 80%+ of the time (data confirmed). Only viable if mispricing is extreme and very late in window. Option F — Version tags in trade records: Add a "bot_version" field to every trade written to analytics. Would allow clean before/after comparisons when parameters change. Currently impossible to distinguish pre/post fix in same analytics file. Option G — Upgrade analyzer to multi-bot: Accept command line argument: python analyzer.py --test or --highroller Currently hardcoded to main bot only. Option H — Add MOM strength threshold: Currently any mom_score > 0 satisfies MOM requirement. Could require mom_score >= 8 (moderate momentum, not just a twitch). Depends on overnight data showing whether weak MOM is profitable. TECHNICAL IMPROVEMENTS DISCUSSED: - Sync btc_scanner.py parameters to match paper_trade.py before going live - Add version tag to each trade record for A/B testing - Dashboard for test/highroller bots (separate port or toggle) - Run analyzer on all bots at once with --all flag ──────────────────────────────────────────────────────────────────────────────── SECTION 10: WHAT TO DO FIRST IN ANY NEW CHAT SESSION ──────────────────────────────────────────────────────────────────────────────── STEP 1 — CHECK BOTS ARE RUNNING: PowerShell: Get-WmiObject Win32_Process -Filter "Name='python.exe'" | Where-Object {$_.CommandLine -like "*paper_trade*"} | Select-Object ProcessId, ParentProcessId, CommandLine Expect 6 processes (3 bots × 2 Windows stub+real pairs). All normal. STEP 2 — PULL AND ANALYZE ALL DATA: Copy and analyze these 3 files: - C:\kalshibot\trade_analytics.json (main bot) - C:\kalshibot\trade_analytics_test.json (test bot) - C:\kalshibot\trade_analytics_highroller.json (high roller) Analyze separately, then compare side by side. Key metrics: overall WR, WR by signal combo, WR by score, recent trend. STEP 3 — KEY QUESTIONS FOR TOMORROW MORNING (April 6): 1. Did MOM-required block lift main bot win rate above 40%? 2. Did highroller win/lose proportionally to main bot (same signal quality)? 3. Did test bot confirm EXP-alone fails at score >= 35? 4. If test bot confirmed failure → repurpose it for next experiment. Best next experiment: Option A (EXP+MOM only, lower threshold). 5. Is MOM-alone recovering or still collapsed at 37%? STEP 4 — IF BOTS DIED OVERNIGHT, RESTART (separate CMD windows): Window 1: cd C:\kalshibot → python paper_trade.py Window 2: cd C:\kalshibot → python paper_trade_test.py Window 3: cd C:\kalshibot → python paper_trade_highroller.py ──────────────────────────────────────────────────────────────────────────────── SECTION 11: RULES FOR CLAUDE IN ANY NEW CHAT ──────────────────────────────────────────────────────────────────────────────── CODE RULES: 1. Always syntax check before telling user to restart: python -m py_compile paper_trade.py 2. Always backup before major changes: Copy to C:\kalshibot\backups\paper_trade_pre_DESCRIPTION.py 3. Never use PowerShell to run Python — always CMD 4. Before ANY code change: state whether it improves WIN RATE first 5. NEVER make unrequested changes — state findings and wait for instruction 6. NEVER reverse a decision the user already made without being asked 7. Syntax check BOTH bots if changing shared logic 8. When reading large files (58KB+) use head/tail parameters GIT RULES: 9. Commit to GitHub after every meaningful change 10. Version as v1.1, v1.2, v2.0 etc — always in commit message with WR 11. main branch = production, test branch = test bot, highroller = highroller 12. NEVER use git checkout to switch branches — it deletes files from disk Instead: use FileSystem copy to create/restore files To restore: git checkout branchname -- filename.py DATA RULES: 13. trade_analytics.json NEVER wiped — permanent learning record forever 14. trade_analytics_test.json NEVER wiped — separate permanent record 15. trade_analytics_highroller.json NEVER wiped 16. $250 starting balance on all bots is intentional — don't change it 17. Session stop loss disabled for paper is intentional — don't change it 18. analyzer.py reads main bot ONLY — that's intentional STRATEGY RULES: 19. No parlays ever under any circumstances 20. No hour blocking ever — needs weeks of data, permanently disabled 21. Trade full 15 min window — do not restrict LAG/MOM to final minutes 22. EXP+LAG block is permanent — never re-enable without overwhelming data 23. MOM required on main bot is current approach — don't remove without asking 24. EXP restricted to final 5 min in main bot — data confirmed, keep it PROCESS RULES: 25. 6 python.exe processes = 3 bots running normally (2 per bot: stub+real) 26. Never kill the WindowsApps stub processes 27. If duplicate real processes exist, kill the older one (lower PID) ──────────────────────────────────────────────────────────────────────────────── SECTION 12: START COMMANDS ──────────────────────────────────────────────────────────────────────────────── START ALL 3 BOTS (3 separate CMD windows, NOT PowerShell): cd C:\kalshibot python paper_trade.py ← Window 1: main bot cd C:\kalshibot python paper_trade_test.py ← Window 2: test bot cd C:\kalshibot python paper_trade_highroller.py ← Window 3: high roller DASHBOARD (after main bot is running): Chrome → http://localhost:8765/dashboard.html ANALYSIS: cd C:\kalshibot python analyzer.py ← reads main bot analytics only LIVE BOT (NOT YET — need 60%+ WR first): cd C:\kalshibot python btc_scanner.py ← REAL MONEY. Sync params first. GITHUB: https://github.com/Thrival/Kalshibot.git main: production code test: test bot highroller: high roller bot TARGET: 200+ paper trades at 60%+ WR on main bot → go live with $250 ═══════════════════════════════════════════════════════════════════════════════ END OF HANDOFF — DO NOT DELETE ANYTHING ABOVE THIS LINE Future updates: append new dated sections below this line only. ═══════════════════════════════════════════════════════════════════════════════