The CONSENSUS strategy is the most sophisticated approach in the Simple Kalshi Bot. It combines two independent signals—PREVIOUS (trend following) and MOMENTUM (BTC price direction)—and only places trades when both agree. This confirmation-based approach includes advanced risk management features like dynamic position sizing, loss caps, and rolling performance monitoring.
Strategy Logic
CONSENSUS requires unanimous agreement between:
PREVIOUS signal : Which side won the last market?
MOMENTUM signal : Is BTC price moving up or down over the last 60 seconds?
Only when both signals point to the same side (both YES or both NO) does the strategy execute a trade.
Why Consensus Works
By requiring two independent signals to align, CONSENSUS:
Filters noise : Reduces false signals from any single indicator
Increases conviction : Higher probability when multiple factors agree
Reduces trade frequency : Only takes high-quality setups
CONSENSUS typically trades less frequently than PREVIOUS or MOMENTUM alone, but with better risk-adjusted returns.
Implementation
Signal Collection
CONSENSUS reuses the signals already computed by PREVIOUS and MOMENTUM:
# bot.py:506-517
if ( "CONSENSUS" , ticker) not in traded_keys:
prev_signal = signals[ticker].get( "PREVIOUS" )
mom_signal = signals[ticker].get( "MOMENTUM" )
if prev_signal and mom_signal and prev_signal == mom_signal:
side = prev_signal # Both agree
price = yes_ask if side == "yes" else no_ask
if price <= 0 :
traded_keys.add(( "CONSENSUS" , ticker))
print ( f " -> [CONSENSUS] Skip - invalid price ( { price } )" )
time.sleep( POLL_SECONDS )
continue
Price Filter
CONSENSUS enforces a maximum entry price:
# bot.py:520-526
if price > CONSENSUS_MAX_PRICE :
traded_keys.add(( "CONSENSUS" , ticker))
print (
f " -> [CONSENSUS] Skip - ask $ { price :.4f} > max $ { CONSENSUS_MAX_PRICE :.2f} "
)
time.sleep( POLL_SECONDS )
continue
CONSENSUS_MAX_PRICE defaults to 0.55 (configurable via env var). This ensures the strategy only enters when risk/reward is favorable.
Dynamic Position Sizing
Unlike simple strategies with fixed stakes, CONSENSUS sizes positions based on bankroll:
# bot.py:528-587
bankroll = consensus_bankroll(trades)
if bankroll <= 0 :
traded_keys.add(( "CONSENSUS" , ticker))
print ( " -> [CONSENSUS] Skip - bankroll depleted" )
time.sleep( POLL_SECONDS )
continue
r_value = max (bankroll * CONSENSUS_RISK_PCT , 0.01 )
target_stake = bankroll * CONSENSUS_RISK_PCT
max_stake = bankroll * CONSENSUS_MAX_RISK_PCT
stake = min ( max (target_stake, 0.01 ), max_stake, bankroll)
contracts = int (stake / price)
if contracts < 1 :
traded_keys.add(( "CONSENSUS" , ticker))
print (
f " -> [CONSENSUS] Skip - stake $ { stake :.2f} too small for ask $ { price :.4f} "
)
time.sleep( POLL_SECONDS )
continue
max_contracts = int (max_stake / price)
contracts = min (contracts, max_contracts)
if contracts < 1 :
traded_keys.add(( "CONSENSUS" , ticker))
print ( " -> [CONSENSUS] Skip - exceeds max risk per trade" )
time.sleep( POLL_SECONDS )
continue
stake = contracts * price
Bankroll calculation tracks realized P&L:
# bot.py:158-164
def consensus_bankroll ( trades ):
"""Current consensus bankroll from realized P&L."""
realized = sum (
float (t.get( "profit_usd" , 0 ))
for t in settled_consensus(trades)
)
return INITIAL_BANKROLL_USD + realized
Loss Caps
CONSENSUS implements daily and weekly loss limits:
# bot.py:535-552
r_value = max (bankroll * CONSENSUS_RISK_PCT , 0.01 )
daily_cap = CONSENSUS_DAILY_LOSS_CAP_R * r_value
weekly_cap = CONSENSUS_WEEKLY_LOSS_CAP_R * r_value
day_pnl, week_pnl = consensus_period_pnl(trades, now)
if day_pnl <= - daily_cap:
traded_keys.add(( "CONSENSUS" , ticker))
print (
f " -> [CONSENSUS] Skip - daily loss cap hit ( { day_pnl :+.2f} <= - { daily_cap :.2f} )"
)
time.sleep( POLL_SECONDS )
continue
if week_pnl <= - weekly_cap:
traded_keys.add(( "CONSENSUS" , ticker))
print (
f " -> [CONSENSUS] Skip - weekly loss cap hit ( { week_pnl :+.2f} <= - { weekly_cap :.2f} )"
)
time.sleep( POLL_SECONDS )
continue
The strategy checks if recent performance exceeds break-even win rate:
# bot.py:188-218
def rolling_consensus_metrics ( trades ):
"""Return rolling consensus performance and break-even win rate."""
settled = settled_consensus(trades)
if not settled:
return {
"sample_size" : 0 ,
"win_rate" : 0.0 ,
"break_even_win_rate" : 1.0 ,
}
window = settled[ - CONSENSUS_ROLLING_WINDOW :]
profits = [ float (t.get( "profit_usd" , 0 )) for t in window]
wins = [p for p in profits if p > 0 ]
losses = [p for p in profits if p <= 0 ]
sample_size = len (window)
win_rate = len (wins) / sample_size if sample_size else 0.0
if wins and losses:
avg_win = sum (wins) / len (wins)
avg_loss = abs ( sum (losses) / len (losses))
break_even = avg_loss / (avg_win + avg_loss) if (avg_win + avg_loss) else 1.0
elif wins and not losses:
break_even = 0.0
else :
break_even = 1.0
return {
"sample_size" : sample_size,
"win_rate" : win_rate,
"break_even_win_rate" : break_even,
}
The strategy halts trading if win rate falls below break-even:
# bot.py:554-565
rolling = rolling_consensus_metrics(trades)
if (
rolling[ "sample_size" ] >= CONSENSUS_ROLLING_WINDOW
and rolling[ "win_rate" ] < rolling[ "break_even_win_rate" ]
):
traded_keys.add(( "CONSENSUS" , ticker))
print (
" -> [CONSENSUS] Skip - rolling win rate below break-even "
f "( { rolling[ 'win_rate' ] * 100 :.1f} % < { rolling[ 'break_even_win_rate' ] * 100 :.1f} %)"
)
time.sleep( POLL_SECONDS )
continue
Configuration
CONSENSUS has extensive configuration options (all via environment variables):
Parameter Default Description INITIAL_BANKROLL_USD500Starting capital for position sizing CONSENSUS_RISK_PCT0.01 (1%)Target stake as % of bankroll CONSENSUS_MAX_RISK_PCT0.02 (2%)Maximum stake as % of bankroll CONSENSUS_MAX_PRICE0.55Highest acceptable entry price CONSENSUS_FEE_PCT0.0Trading fees (if applicable) CONSENSUS_ROLLING_WINDOW30Number of recent trades for performance check CONSENSUS_DAILY_LOSS_CAP_R3Max daily loss (in R multiples) CONSENSUS_WEEKLY_LOSS_CAP_R8Max weekly loss (in R multiples)
The “R” in loss caps refers to r_value = bankroll * CONSENSUS_RISK_PCT. For example, with a $500 bankroll and 1% risk:
R = $5
Daily cap = 3R = $15
Weekly cap = 8R = $40
Risk Characteristics
Advantages
Signal confirmation : Two independent signals reduce false positives
Dynamic sizing : Stakes scale with bankroll (% risk model)
Loss protection : Daily/weekly caps prevent catastrophic drawdowns
Performance awareness : Stops trading when edge disappears
Price discipline : Only enters at favorable prices
Limitations
Lower frequency : Requires both signals to align, reducing trade count
Complexity : More failure modes and configuration parameters
Whipsaw risk : Can hit loss caps during choppy periods before edge returns
When to Use
CONSENSUS is ideal for:
Live trading : The risk management makes it suitable for real capital
Longer-term operation : Daily/weekly caps smooth out variance over time
High-conviction setups : When you want quality over quantity
Bankroll preservation : Dynamic sizing protects against ruin
During extended drawdowns, CONSENSUS may stop trading entirely if:
Bankroll is depleted
Daily/weekly loss caps are hit
Rolling win rate falls below break-even
This is a feature, not a bug —it prevents throwing good money after bad.
CONSENSUS_2 Variant
The CONSENSUS_2 variant adds the price filter from PREVIOUS_2:
# bot.py:645-716
if ( "CONSENSUS_2" , ticker) not in traded_keys:
prev_signal = signals[ticker].get( "PREVIOUS" )
mom_signal = signals[ticker].get( "MOMENTUM" )
if prev_signal and mom_signal and prev_signal == mom_signal:
side = prev_signal
price = yes_ask if side == "yes" else no_ask
if 0 < price <= DEAL_MAX_PRICE : # Wait for good price
# ... same risk management as CONSENSUS ...
CONSENSUS_2 waits for the consensus side to reach $0.45 or less. This:
Further reduces trade frequency
Improves risk/reward on entries
May miss strong trending opportunities
Standalone Bot
CONSENSUS has a production-ready standalone implementation in consensus.py:
# consensus.py:268-282
print ( "=" * 60 )
print ( "CONSENSUS STRATEGY BOT - REAL TRADING" )
print ( "=" * 60 )
print ( f "Series: { SERIES_TICKER } " )
print ( f "Stake: $ { STAKE_USD } per trade" )
print ( f "Momentum window: { MOMENTUM_WINDOW_SECONDS } s" )
print ( f "Poll interval: { POLL_SECONDS } s" )
print ( f "Trades CSV: { TRADES_CSV } " )
print ( f "DRY RUN: { dry_run } " )
Key differences from bot.py CONSENSUS:
Uses Kalshi API authentication (RSA key signing)
Supports real order execution (not just mock trades)
Has DRY_RUN mode for testing
Separate CSV output (data/consensus_trades.csv)
Running the Standalone Bot
Required environment variables:
KALSHI_API_KEY_ID = your_api_key_id
KALSHI_PRIVATE_KEY_PATH = ~/.ssh/kalshi_private_key.pem
KALSHI_USE_DEMO = true # or false for production
DRY_RUN = true # true = simulate, false = real trades
Run the bot:
Set DRY_RUN=false only when you’re ready to trade with real money. Start with KALSHI_USE_DEMO=true to test against Kalshi’s demo environment.
Example Trade Flow
Market A settles at YES
Previous market result: BTC went up
BTC momentum check
Current BTC price vs. 60s ago: 95 , 450 v s . 95,450 vs. 95 , 450 v s . 95,200 (+0.26%)
Consensus agreement
Both signals = YES → CONSENSUS activates
Risk checks
✓ Price = 0.48 ( < m a x 0.48 (< max 0.48 ( < ma x 0.55)
✓ Bankroll = 515.30
✓ Daily P&L = - 2.50 (above -15.46 cap)
✓ Weekly P&L = + 12.80 (above -$41.22 cap)
✓ Rolling win rate = 56.7% (above 52.3% break-even)
Position sizing
Target stake = 515.30 × 1 515.30 × 1% = 515.30 × 1 5.15
Max stake = 515.30 × 2 515.30 × 2% = 515.30 × 2 10.31
Actual stake = $5.15 (within limits)
Contracts = 10 (int(5.15 / 5.15 / 5.15/ 0.48))
Final stake = 4.80 ( 10 c o n t r a c t s × 4.80 (10 contracts × 4.80 ( 10 co n t r a c t s × 0.48)
Execute trade
Buy 10 YES contracts at 0.48 = 0.48 = 0.48 = 4.80 total
Settlement
Market settles YES:
Payout: $10.00
Gross profit: $5.20
Fee: $0.00
Net profit: $5.20
Console output during trading:
[12:34:56] [LIVE] KXBTC15M-24MAR05-T1245 ( 180s ) | yes = $0 .52 no = $0 .48 | BTC = 95,234 | P & L: $ +15.40
PREVIOUS signal: yes (from KXBTC15M-24MAR05-T1230 )
MOMENTUM signal: yes (BTC +0.245% )
>>> CONSENSUS SIGNAL: YES <<<
Placing order: BUY 10 yes @ $0 .48 ($4.80 total )
Order placed! ID: 01J9X...
Final stats:
==========================================================
STOPPED - FINAL STATS
==========================================================
Total trades: 47
Wins: 28 | Losses: 17 | Pending: 2
Total staked: $234 .50
Total profit: $ +42.30
ROI: 18.0%
PREVIOUS Strategy Learn about the trend-following signal component
MOMENTUM Strategy Understand the BTC price direction signal
Configuration Configure CONSENSUS risk parameters