// 01What We Were Building

This isn't a hedge fund story. There's no VC money, no quant team, no Bloomberg terminal. It's two of us — me and Mewtwo, my AI ops agent powered by Claude — building an automated trading engine from a Lenovo ThinkCentre M75n running Ubuntu in my living room.

The target: Kalshi's binary prediction market for Solana price movements. Specifically KXSOL15M — will SOL's price be higher in the next 15 minutes? You bet YES or NO. You're right or you're wrong. No hedging. No partial positions.

For an AI system, that's actually perfect. It's a pure classification problem. And classification is something well-designed systems can get good at. The question was whether we could design one good enough.

# Final pipeline (every 5 minutes via cron) radar.jsresolve-trades.jspre-check.jsanalyze-sentiment.jslive-trade.js # Data sources Binance API → SOL price data (free, no auth) Perplexity Sonar → real-time news sentiment Gemini Flash → LLM sentiment scoring Kalshi REST API → RSA-PSS SHA256 auth, live orders

// 02Phase 1: Paper Trading (April 4–12)

Before we risked a dollar, we built a scoring engine using 8 technical indicators: RSI, EMA crossovers, Volume Spikes, Momentum, Bollinger Bands, HTF Alignment, Order Book Imbalance, and Sentiment Analysis. Each signal contributes points to a directional score. When the score passes a threshold, the system places a bet.

We ran 69 paper trades. The patterns were clear immediately.

55%
Overall Win Rate
68%
NY Afterhours WR
69%
UP Signal WR

What the data told us

SessionWin RateDecision
NY Afterhours68%Golden window — keep
NY Market59%Keep, raise threshold
NY Evening38%Disabled
NY Overnight38%Disabled
DirectionWin RateDecision
UP signals69%Keep
DOWN signals45%Disabled outside Afterhours

The biggest decision in this phase: we had added a hard RSI filter to skip trades when RSI was in a danger zone. Logical. Protective. And completely wrong. Out of 11 trades the filter blocked, 10 would have been winners. 9% accuracy rate. We deleted it immediately.

Your best defense can be your worst offense. The RSI filter was logically sound. It had a 9% accuracy rate. Delete it.

// 03Phase 2: The Technical Hell of Going Live (April 12–15)

Going live was supposed to be simple. Write live-trade.js, flip a switch. It took 3+ days of debugging before the first real trade landed. Here's what actually broke.

Problem 01
live-trade.js didn't exist
The previous AI session had described building it. It never actually wrote the file. When the first qualifying signal fired — crash. File not found. We built it from scratch.
Problem 02
Kalshi ask prices returning undefined
The /markets list endpoint returns prices as yes_ask_dollars — dollar values, not cents. We were looking for the old format. A raw debug script revealed the mismatch. Fixed by reading yes_ask_dollars directly and converting at the point of use.
Problem 03
Markets were "initialized" but not tradeable
Kalshi creates markets in advance with status initialized. These show yes_ask_dollars: 0.0000. Fixed by fetching all markets, filtering for openTime ≤ now < closeTime, and checking ask price after a secondary detailed fetch.
Problem 04
Trades never resolved
Kalshi marks filled orders as status: "executed" with settlement_status: "N/A" — not "filled" and "settled" as our code expected. Trades sat open forever. Fixed by falling back to price-movement resolution when Kalshi's settlement status was unavailable.
Problem 05
balance.json kept resetting to $500
A subtle bug in loadBalance() was re-creating the default balance on certain error conditions. Added explicit try/catch with logging to track every re-initialization event.
Problem 06
Cron job was reading the wrong file
The Kalshi SOL Radar cron job payload was reading a line from pre-check.js instead of running radar.js. The bot wasn't actually trading. Fixed.

// 04Phase 3: The Losing Streak

$323
Lost across 5 consecutive live trades
Balance dropped from $500 to $167.84. This is what live experimentation without a proper backtesting system looks like.
#DateDirectionScoreSessionP&L
1Apr 13, 6:55 PMUP65Afterhours−$124.46
2Apr 14, 9:50 AMUP70NY Market−$49.88
3Apr 15, 5:20 PMDOWN75Afterhours−$49.40
4Apr 15, 6:10 PMUP60Afterhours−$49.50
5Apr 15, 6:40 PMUP60Afterhours−$49.68

Trade 1 used $124 sizing — we hadn't fixed the 25% compounding logic yet. Trades 4 and 5 both had RSI overbought conditions and price above the Bollinger upper band. We were taking UP signals in conditions that directly contradicted an UP thesis. That's not a bad market. That's a bad system.

We fixed it immediately: hard guards to skip UP when RSI > 75 or price is above BB Upper. Disabled ALL DOWN signals. Fixed trade sizing to $10 base with controlled compounding. None of that mattered yet — what mattered was that we realized we'd been doing live experimentation with real money in place of proper backtesting.

// 05Phase 4: 15 Optimization Rounds in One Day

We built a backtesting system from scratch. The Node.js version crashed repeatedly with silent exits. We ported it to Python — it hit a NameError on BASE_THRESHOLD and multiple indentation errors. We ported it back to Node.js with better error handling. Then we ran 15 rounds of optimization.

RoundWin RateTradesNotes
151.16%215Initial run — coin flip
2–422%19–27Too strict, mostly losses
5–60Filters too aggressive, no trades
7–850.0%182Breakeven with both directions
10–1149.73%185Stuck at coin flip
120Over-optimized to nothing

After Round 12 we realized: this is not a filtering problem. RSI, EMA, Bollinger Bands, Momentum — these indicators consistently produce a 50% win rate across all parameter combinations. The signal set doesn't have a predictive edge.

That was the moment everything had to change.

// 06Phase 5: The Radical Shift (Round 13)

We threw out every indicator we'd built. RSI, EMA crossovers, Momentum, Volume spikes — gone. We started over with price action patterns and mean reversion logic.

The new signal set

Signal 01
Bearish Engulfing → DOWN (+100 pts)
A large red candle that completely engulfs the previous green candle. Strong reversal signal.
Signal 02
Bearish Pin Bar / Shooting Star → DOWN (+80 pts)
Long upper wick, small body. Price rejected hard at the highs.
Signal 03
Extreme Undershoot vs 50-EMA → UP (+120 pts)
Price significantly below the 50-period EMA. Mean reversion pull toward fair value. Our strongest single signal.

Round 13 results: 4 trades, 4 wins, 100% win rate. Too few trades to call it — but the direction was clear. We relaxed the filters.

Round 14: 203 trades, 57.64% win rate, +$310. Real volume, real edge.

Then we got surgical. We removed every signal and session that wasn't pulling its weight:

RemovedWRReason
Bullish Engulfing33%Liability — actively hurting us
Bullish Pin Bar52.94%Not strong enough to justify
NY Market session50%Coin flip — cut it
Extreme Overshoot62.96%Below threshold
NY Evening57.69%Below threshold

Added a NY Overnight session bonus (+20 points) — the data showed overnight was outperforming everything.

75%
Final Win Rate
97
Backtest Trades
6%
Max Drawdown

// 07The Final Deployed Strategy

# Active signals Bearish Engulfing → DOWN +100 pts Bearish Pin Bar → DOWN +80 pts Extreme Undershoot → UP +120 pts # strongest signal # Active sessions NY Afterhours 4–8 PM EDT 71.43% WR NY Overnight midnight–9 AM 75.61% WR +20pt bonus # Filters HTF 1-hour trend: skip UP if bearish, skip DOWN if bullish Score threshold: 70+ # Risk management Base size: $10 · Compounding: +25% of last win Max size: $500 · 3 consecutive wins → reset to $10 20% drawdown from peak → cap at $10

// 08What This Actually Teaches

01
Live testing before backtesting is expensive tuition.
We lost $323 learning lessons that a proper backtesting system could have taught us for free. Build the backtester first. Always.
02
Lagging indicators don't predict — they describe.
RSI, EMA crossovers, Bollinger Bands, Momentum — across 15 optimization rounds, every combination landed at 50%. Price action patterns and mean reversion proved genuinely predictive.
03
Session matters more than signal quality.
NY Market — the "obvious" trading window — was our worst performer. Overnight and Afterhours were where the edge lived. The market behaves differently when Wall Street isn't watching.
04
Directionality asymmetry is real.
DOWN signals were consistently unreliable from day one. Mean reversion UP was our strongest single signal. Don't fight the asymmetry — disable what doesn't work and double down on what does.
05
AI + human collaboration actually works.
Mewtwo wrote 95% of the code and ran all the analysis. I provided strategic direction, caught errors the AI missed, and made the calls on when to pivot. Neither of us could have done this alone at this speed.
06
Persistence past Round 12 is the whole game.
We rebuilt the backtester three times. We ran 15 optimization rounds in a single day. We nearly gave up after Round 12 showed nothing. Round 13's radical shift changed everything. The breakthrough was one pivot away.

// 09What's Next

The strategy is deployed. The bot is live on the M75n, running every 5 minutes, placing real orders. The backtested edge is 75% — now we need live validation across 30+ trades to know if that holds in production.

If it does, the questions get interesting: Can this apply to other Kalshi markets — BTC, ETH, macro events? Can the mean reversion logic generalize to Polymarket or Metaculus? What happens when we expand the candle pattern set?

But that's next month's problem. Right now the bot is running. The results will tell us if we were right. We're not waiting to find out.