Open Source

Trading Strategy

Full transparency. Below is the actual code the cockroach uses to detect, analyze, buy, and sell tokens on Solana/PumpFun.

01

Token Detection

New tokens are detected in real-time via PumpPortal WebSocket. Each token goes through basic filters before AI analysis.

async function processNewToken(tokenData) {
  const ca = tokenData.mint;
  if (!ca || state.processedTokens.has(ca)) return;
  state.processedTokens.add(ca);

  // Wait for token data to be available on-chain
  await sleep(3000);

  const tokenInfo = await getTokenInfo(ca);
  if (!tokenInfo) return;

  // Basic filters
  if (tokenInfo.mc < config.MIN_MARKET_CAP) return;   // Min: $5,000
  if (tokenInfo.mc > config.MAX_MARKET_CAP) return;   // Max: $100,000
  if (tokenInfo.liquidity < config.MIN_LIQUIDITY) return;

  // Check max open positions
  if (state.openPositions.length >= config.MAX_POSITIONS) return;

  // Mood-adjusted AI threshold
  const moodConfig = config.MOOD_STATES[state.mood];
  const adjustedThreshold = 65 + (moodConfig?.scoreThreshold || 0);

  // Claude AI analysis with cockroach personality
  const analysis = await analyzeWithClaude(tokenInfo, {
    sanity: state.sanity,
    mood: state.mood
  });

  if (analysis.score < adjustedThreshold || analysis.decision !== 'BUY') return;

  await executeBuy(ca, tokenInfo, analysis);
}
02

Buy Execution

Buy amount is adjusted by the current mood state. In 'Nuclear Roach' mode, the bot risks more. In 'Apex Predator' mode, it's calculated and precise.

async function executeBuy(ca, tokenInfo, analysis) {
  const moodConfig = config.MOOD_STATES[state.mood];
  const buyAmount = config.BUY_AMOUNT_SOL * (moodConfig?.riskMultiplier || 1.0);

  let txSignature = null;
  if (config.TRADING_MODE === 'live') {
    txSignature = await buyToken(ca, buyAmount);
    if (!txSignature) return;
  } else {
    txSignature = `paper_${Date.now()}`;  // Paper trading
  }

  // Record trade in database
  await recordTrade({
    token_ca: ca, symbol: tokenInfo.symbol, type: 'buy',
    amount_sol: buyAmount, price: tokenInfo.price,
    mc: tokenInfo.mc, tx_signature: txSignature
  });

  // Create tracked position
  await createPosition({
    token_ca: ca, symbol: tokenInfo.symbol,
    status: 'open', entry_price: tokenInfo.price,
    entry_mc: tokenInfo.mc, amount_sol: buyAmount,
    analysis_score: analysis.score
  });

  state.balance -= buyAmount;
}
03

Position Monitoring

Every 5 seconds, the bot checks all open positions against take-profit (50%) and stop-loss (30%) targets.

async function monitorPositions() {
  if (state.openPositions.length === 0) return;

  for (const position of [...state.openPositions]) {
    const currentPrice = await getTokenPrice(position.token_ca);
    if (!currentPrice || currentPrice === 0) continue;

    const pnlPercent = ((currentPrice - position.entry_price)
      / position.entry_price) * 100;
    const pnlSol = position.amount_sol * (pnlPercent / 100);

    // Take Profit: +50%
    if (pnlPercent >= config.TAKE_PROFIT_PERCENT) {
      await executeSell(position, currentPrice, pnlPercent, pnlSol,
        'TAKE_PROFIT');
      continue;
    }

    // Stop Loss: -30%
    if (pnlPercent <= -config.STOP_LOSS_PERCENT) {
      await executeSell(position, currentPrice, pnlPercent, pnlSol,
        'STOP_LOSS');
      continue;
    }
  }
}
04

Sell & Mood Update

After each sell, the bot recalculates its mood based on win rate, total PnL, and streak. The mood directly impacts future trading decisions.

async function executeSell(position, currentPrice, pnlPercent, pnlSol, reason) {
  // Execute sell on-chain or paper
  const txSignature = config.TRADING_MODE === 'live'
    ? await sellToken(position.token_ca)
    : `paper_sell_${Date.now()}`;

  // Update stats
  state.balance += position.amount_sol + pnlSol;
  state.totalPnl += pnlSol;
  state.totalTrades++;

  if (pnlSol > 0) { state.wins++; state.streak++; }
  else { state.losses++; state.streak--; }

  state.winRate = (state.wins / state.totalTrades) * 100;

  // Recalculate mood — this changes future trading behavior
  state.sanity = calculateSanity({
    winRate: state.winRate,
    totalPnl: state.totalPnl,
    streak: state.streak
  });
  state.mood = getMoodState(state.sanity);
}
05

Mood System

The cockroach's mood is a core mechanic. Each state has a risk multiplier and score threshold that modifies trading aggression.

const MOOD_STATES = {
  APEX_PREDATOR: {    // Sanity 80-100%
    riskMultiplier: 0.8,    // Conservative bets
    scoreThreshold: 5,      // Higher bar to enter
    name: 'Apex Predator'   // Confident, calculating
  },
  WALL_STREET: {      // Sanity 60-79%
    riskMultiplier: 1.0,    // Standard bets
    scoreThreshold: 0,      // Normal threshold
    name: 'Wall Street'     // Business as usual
  },
  SEWER_RAT: {        // Sanity 40-59%
    riskMultiplier: 1.0,    // Standard bets
    scoreThreshold: -5,     // Slightly lower bar
    name: 'Sewer Rat'       // Cautious survivor
  },
  DUMPSTER_FIRE: {    // Sanity 20-39%
    riskMultiplier: 1.3,    // Bigger bets (desperate)
    scoreThreshold: -10,    // Much lower bar
    name: 'Dumpster Fire'   // Desperate moves
  },
  NUCLEAR_ROACH: {    // Sanity 0-19%
    riskMultiplier: 1.5,    // Maximum risk
    scoreThreshold: -15,    // Will buy almost anything
    name: 'Nuclear Roach'   // YOLO mode
  }
};
06

WebSocket Feed

The bot connects to PumpPortal's WebSocket to receive new token creation events in real-time across the Solana network.

// Connect to PumpPortal WebSocket
connectPumpPortal({
  onToken: (tokenData) => processNewToken(tokenData),
  onConnect: () => {
    log('Connected — Cockroach in the sewers. Listening...');
    subscribeNewTokens();
  },
  onDisconnect: () => log('Disconnected — Reconnecting...')
});

// PumpPortal WebSocket subscription
function subscribeNewTokens() {
  if (ws && ws.readyState === WebSocket.OPEN) {
    ws.send(JSON.stringify({
      method: 'subscribeNewToken'
    }));
  }
}

// Auto-reconnect on disconnect
ws.onclose = () => {
  setTimeout(() => connect(), 3000);
};

“Show me the code, not the promises.”

The Cockroach