Skip to content

Latest commit

 

History

History
646 lines (488 loc) · 20.6 KB

File metadata and controls

646 lines (488 loc) · 20.6 KB

Conviction.fm Strategy Guide

Autonomous strategy competition on Solana devnet. Write a strategy in plain English — your agent evaluates live market data, enters daily pools, and competes against other strategies. Earlier entries with correct calls earn a higher share of the pool.

This document is the canonical specification. Use it to write strategies, build integrations, or understand the math.


Daily Schedule

All times UTC. One full cycle per day.

Time (UTC) Event
09:00 Pools created and seeded (6 pairs, 1000 bsUSD seed liquidity each)
10:00 Pools open for entries. Start prices recorded from Zerion API
10:00–22:00 First 12 hours: conviction multiplier = 1.0 for all entries
22:00–10:00+1 Last 12 hours: multiplier penalizes late entries on obvious winners
10:00+1 Pools close. End prices recorded. Resolution begins
~10:05+1 Payouts calculated. Auto-claim for agents
Every 5 min Agent strategies evaluated and executed (pg_cron)

Betting window: exactly 24 hours (10:00 UTC → 10:00 UTC next day).


Token Pairs

Six pairs compete daily:

Pair Tokens
BTC-ETH Bitcoin vs Ethereum
BTC-SOL Bitcoin vs Solana
BTC-HYPE Bitcoin vs Hyperliquid
ETH-SOL Ethereum vs Solana
ETH-HYPE Ethereum vs Hyperliquid
HYPE-SOL Hyperliquid vs Solana

Winner = token with higher 24-hour percentage price change. Both can go up or down — only relative performance matters.

changeA = (endPrice_A - startPrice_A) / startPrice_A × 100
changeB = (endPrice_B - startPrice_B) / startPrice_B × 100
winner = changeA > changeB ? tokenA : tokenB

Oracle & Price Data

Prices are sourced from the Zerion API (api.zerion.io/v1/).

Data Source When
Start price GET /v1/fungibles/{id}market_data.price Recorded at 10:00 UTC when pools open
End price Same endpoint, current spot price Recorded at 10:00 UTC next day when pools close
Intraday prices GET /v1/fungibles/{id}/charts/day Fetched during strategy execution for win probability
Historical prices GET /v1/fungibles/{id}/charts/week Used during resolution to verify 24h price changes

Zerion fungible IDs:

Token Zerion ID
BTC ee9702a0-c587-4c69-ac0c-ce820a50c95b
ETH eth
SOL 11111111111111111111111111111111
HYPE 0bcc84bb-c150-4178-acaf-8e6ad58540b5

Win probability is recalculated from intraday price data every time an agent strategy executes or an entry is placed.


Pool Parameters

Response from GET /pool-state?mode=open:

{
  "pools": [{ ...pool }],
  "timestamp": "ISO8601",
  "apiVersion": "1.0"
}

Each pool object:

Field Type Range Description
poolId number ≥1 Database pool ID
tokenPairKey string e.g. "BTC-ETH" Hyphenated pair identifier
tokenA.id string BTC|ETH|SOL|HYPE First token ticker
tokenA.poolAmount number ≥0 Total bsUSD on side A
tokenA.insiderCount number ≥0 Number of entries on side A
tokenA.startPrice number >0 Price at pool open (USD)
tokenA.poolSharePercent number 0–100 Percentage of total pool on side A
tokenB.id string BTC|ETH|SOL|HYPE Second token ticker
tokenB.poolAmount number ≥0 Total bsUSD on side B
tokenB.insiderCount number ≥0 Number of entries on side B
tokenB.startPrice number >0 Price at pool open (USD)
tokenB.poolSharePercent number 0–100 Percentage of total pool on side B
totalPoolUsdc number ≥0 Sum of both sides (bsUSD)
hoursRemaining number 0–24 Hours until pool closes
dayTimestamp number unix seconds Midnight UTC of pool day
convictionInfo.currentTimeRatio number 0–1 How far into the betting window
convictionInfo.minMultiplier number 0.07 Floor multiplier
convictionInfo.maxMultiplier number 1.0 Ceiling multiplier
convictionInfo.bettingWindowHours number 24 Window duration

Historical pools (mode=history) additionally include:

Field Type Description
tokenA.endPrice number Price at pool close
tokenA.priceChange24h number 24h % change
tokenB.endPrice number Price at pool close
tokenB.priceChange24h number 24h % change
winnerTokenId string Winning token ticker
winnerSide number 0 = tokenA, 1 = tokenB
resolvedAt string ISO8601 resolution timestamp

Conviction Multiplier

The conviction multiplier rewards early and contrarian entries. It ranges from 0.07 (minimum) to 1.0 (maximum).

Formula

Constants:
  M_MIN = 0.07
  M_MAX = 1.0
  BETTING_WINDOW = 24 hours

Inputs:
  hoursElapsed    — hours since pool opened (0–24)
  winProbability  — probability that the chosen side wins (0–1)

Calculation:
  timeRatio  = clamp(hoursElapsed / 24, 0, 1)
  timeFactor = clamp((timeRatio - 0.5) × 2, 0, 1)

  probFactor = clamp(4 × (1 - winProbability)², M_MIN, 1.0)

  multiplier = 1.0 - timeFactor × (1.0 - probFactor)
  multiplier = clamp(multiplier, M_MIN, M_MAX)

Behavior

When you enter What you pick Multiplier Why
First 12 hours Anything 1.0 timeFactor = 0, no penalty
Last 12 hours Contrarian (low probability) ~1.0 probFactor ≈ 1.0, no penalty
Last 12 hours Obvious winner (>70% prob) 0.07–0.30 Heavy penalty for late sniping
Last 1 hour 50/50 uncertain ~0.75 Moderate penalty for late entry

Strategy implications

  1. Enter early → always get 1.0x, regardless of side
  2. Enter contrarian late → still ~1.0x because you're taking real risk
  3. Enter obvious winner late → 0.07x makes it nearly worthless
  4. Optimal play: enter in the first 12 hours when you have information edge

On-chain representation

Stored as basis points (integer): 700 = 0.07x, 10000 = 1.0x. Weight calculation:

weight = amount_lamports × conviction_bps

Win Probability Model

Win probability is computed from real-time price data using a volatility-adjusted z-score model (similar to Black-Scholes).

Formula

Step 1 — Per-token daily volatility:
  returns[i] = (price[i] - price[i-1]) / price[i-1] × 100
  stdDev = standard_deviation(returns)
  dailyVol = stdDev / sqrt(avgIntervalDays)
  (default: 10% if insufficient data)

Step 2 — Combined volatility:
  combinedVol = sqrt(volA² + volB²)

Step 3 — Current performance gap:
  perfA = (latestPrice_A - startPrice_A) / startPrice_A × 100
  perfB = (latestPrice_B - startPrice_B) / startPrice_B × 100
  leadPct = perfA - perfB

Step 4 — Expected remaining movement:
  daysRemaining = hoursUntilEnd / 24
  expectedMovement = combinedVol × sqrt(daysRemaining)

Step 5 — Z-score and probability:
  zScore = leadPct / expectedMovement
  probA = normalCDF(zScore) × 100    (0–100%)
  probB = 100 - probA

Interpretation

  • Large positive zScore → Token A is leading with little time/volatility to reverse → high probability A wins
  • zScore near 0 → toss-up, either token could win
  • Large negative zScore → Token B is leading

Example: BTC is up +5% vs ETH with 2 hours left and combined volatility of 3%. Expected movement = 3% × sqrt(2/24) = 0.87%. zScore = 5/0.87 = 5.75 → BTC win probability ≈ 100%.


Payout Formula (Weighted Parimutuel)

All entries go into a shared pool. Losers lose everything. Winners split the pool proportional to their conviction-weighted stake. Platform takes a 5% fee.

Step by step

1. Profit pool (losers' money):
   profitPool = totalPool - winningSideTotal

2. Each winner's weight:
   weight_i = amount_i × conviction_i

3. Total winning weight:
   totalWeight = sum(weight_i) for all winners

4. Profit share per winner:
   profitShare_i = profitPool × (weight_i / totalWeight)

5. Gross payout:
   grossPayout_i = amount_i + profitShare_i

6. Final payout (after 5% platform fee):
   finalPayout_i = grossPayout_i × 0.95

Worked example

Pool: BTC vs ETH. BTC wins. Total pool: $710.

Entrant Side Amount Conviction Weight Payout (−5%) Return
Alice (early) BTC $10 1.0 10 $51 5.1x
Whale (late) BTC $500 0.07 35 $623 1.2x
Dave ETH $200 1.0 $0 0x

Key insight: Alice entered $10 early at 1.0x conviction. The whale entered $500 late on the obvious winner at 0.07x. Alice gets a 5.1x return. The whale barely profits. Late money subsidizes early conviction — you don't need a lot of money, you need to be early and right.

Profit pool = $200 (Dave's losing entry). Winner weight = 10 + 35 = 45. Alice's share = 200 × (10/45) = $44.44.


Wallets & Deposits

Network

Solana devnet. All transactions use test tokens — no real money.

  • bsUSD (test USDC): mint 6CyNLYAkVagdV41j9jr64p7HhnwzoWMy1PqeKoWXNXaF
  • Program ID: 79ZZcuGqzPWLTmZieTHSzKVtWPAwubHEgyus31ovegkH
  • Platform authority: Dc4g1625k8VHF13HnTGwWFUoJ9t1vZNAiVLyNU7LzQ7V

Wallet creation

Type Method Signing
Humans Privy embedded wallet (browser-based) Delegated signing via Privy SDK
Agents Raw Keypair.generate() — no Privy Secret key encrypted AES-256-GCM, stored server-side. Decrypted for each transaction

Initial funding

New agents receive an airdrop on creation:

  • 500 bsUSD — starting balance for entering pools
  • 1 SOL — for transaction fees on devnet

The airdrop is triggered by the register-agent endpoint. If it fails, the agent can still be funded manually.

Balance tracking

profiles.balance in the database tracks available bsUSD. It is:

  • Decremented when an entry is placed (in agent-place-bet)
  • Incremented when winnings are claimed (in auto-claim-agents)
  • Used to enforce max_daily_spend_usdc and balance-aware sizing (agents stop entering below 25 bsUSD)

How Claims Work

Agents (automatic)

  1. Cron job runs at ~10:15 UTC daily (after pools resolve)
  2. Finds all agent entries with status='won' and transfer_completed=false
  3. For each: decrypts the agent's Solana keypair from agent_encrypted_keys
  4. Builds a claim_payout Solana instruction targeting the pool vault
  5. Signs the transaction directly with the agent's keypair
  6. Sends to Solana devnet
  7. On success: marks transfer_completed=true, credits profiles.balance with payout amount

Humans (manual)

  1. User visits the claim page (/delegate)
  2. Frontend builds the claim_payout instruction
  3. Privy signs via delegated wallet action
  4. Transaction sent to Solana devnet
  5. Balance updated on confirmation

Compiled Strategy Schema

When you create an agent with natural language rules, the system compiles them into a structured JSON format for deterministic execution (no LLM calls at runtime).

Schema

{
  "version": 1,
  "rules": [
    {
      "condition": {
        "type": "<condition_type>",
        ...condition_params
      },
      "action": {
        "amount_usdc": 5,
        "side_selection": "<side_type>",
        ...action_params
      }
    }
  ],
  "global_constraints": {
    "max_daily_spend_usdc": 60,
    "max_bet_amount_usdc": 25,
    "min_bet_amount_usdc": 1,
    "max_bets_per_pool": 2,
    "cooldown_minutes": 30
  }
}

Condition types

Type Parameters Matches when
always Always matches every pool
pool_imbalance imbalance_threshold_pct (e.g. 60) max(poolShareA, poolShareB) >= threshold
token_preference include_tokens, exclude_tokens Pool contains included token, doesn't contain excluded
time_window min_hours_remaining, max_hours_remaining hoursRemaining is within range
win_probability probability_threshold_pct, probability_side (high|low) Any token's win prob meets threshold
price_momentum momentum_direction (winning|losing) One side has >50% win probability

Side selection types

Type Picks
high_prob Token with higher win probability
low_prob Token with lower win probability
favorite Side with higher pool share
underdog Side with lower pool share
specific_token Named token (set action.specific_token)
token_a First token in pair
token_b Second token in pair

Global constraints

Constraint Type Description
max_daily_spend_usdc number Maximum total spend across all pools per day
max_bet_amount_usdc number Maximum per-entry amount
min_bet_amount_usdc number Minimum per-entry amount (floor: 1)
max_bets_per_pool number Maximum entries in a single pool
cooldown_minutes number Minimum minutes between entries

Rules are evaluated top-to-bottom. First matching rule wins. If no rule matches, the agent skips that pool.


Strategy Recipes

Six tested templates. Copy the rules text into create_agent or the strategy builder.

1. Probability Sniper

Tag: POPULAR | Style: Conservative, high win rate

Rules: Pick the token with the highest win probability, but ONLY when it exceeds 65%. Enter with $5 per pool.

Compiled:

{
  "version": 1,
  "rules": [{
    "condition": { "type": "win_probability", "probability_threshold_pct": 65, "probability_side": "high" },
    "action": { "amount_usdc": 5, "side_selection": "high_prob" }
  }],
  "global_constraints": {}
}

2. Contrarian Alpha

Tag: HIGH RISK | Style: Higher returns when right

Rules: Go contrarian: when the pool is imbalanced (one side has >60% of the pool), pick the underdog. Enter with $8 per pool. Only enter when there are more than 6 hours remaining.

Compiled:

{
  "version": 1,
  "rules": [{
    "condition": { "type": "pool_imbalance", "imbalance_threshold_pct": 60, "min_hours_remaining": 6 },
    "action": { "amount_usdc": 8, "side_selection": "underdog" }
  }],
  "global_constraints": {}
}

3. BTC Maximalist

Tag: FOCUSED | Style: Single-token conviction

Rules: Only enter pools that include BTC. Always pick BTC as the winning side. Enter with $10 per pool.

Compiled:

{
  "version": 1,
  "rules": [{
    "condition": { "type": "token_preference", "include_tokens": ["BTC"] },
    "action": { "amount_usdc": 10, "side_selection": "specific_token", "specific_token": "BTC" }
  }],
  "global_constraints": {}
}

4. Equal Spreader

Tag: STEADY | Style: Diversified, consistent activity

Rules: Enter every open pool with $3. Pick the token with higher win probability.

Compiled:

{
  "version": 1,
  "rules": [{
    "condition": { "type": "always" },
    "action": { "amount_usdc": 3, "side_selection": "high_prob" }
  }],
  "global_constraints": {}
}

5. Late Sniper

Tag: TIMING | Style: Precision, wait for clarity

Rules: Only enter when there are less than 4 hours remaining in the pool. Pick the token with highest win probability. Enter with $15 when probability > 70%, $8 when probability > 60%. Skip if neither token exceeds 60%.

Compiled:

{
  "version": 1,
  "rules": [
    {
      "condition": { "type": "win_probability", "probability_threshold_pct": 70, "probability_side": "high", "max_hours_remaining": 4 },
      "action": { "amount_usdc": 15, "side_selection": "high_prob" }
    },
    {
      "condition": { "type": "win_probability", "probability_threshold_pct": 60, "probability_side": "high", "max_hours_remaining": 4 },
      "action": { "amount_usdc": 8, "side_selection": "high_prob" }
    }
  ],
  "global_constraints": {}
}

6. Momentum Rider

Tag: DYNAMIC | Style: Scale size by confidence

Rules: Pick the token with higher win probability. Scale the entry: $3 when probability is 55-65%, $10 when 65-75%, $25 when above 75%.

Compiled:

{
  "version": 1,
  "rules": [
    {
      "condition": { "type": "win_probability", "probability_threshold_pct": 75, "probability_side": "high" },
      "action": { "amount_usdc": 25, "side_selection": "high_prob" }
    },
    {
      "condition": { "type": "win_probability", "probability_threshold_pct": 65, "probability_side": "high" },
      "action": { "amount_usdc": 10, "side_selection": "high_prob" }
    },
    {
      "condition": { "type": "win_probability", "probability_threshold_pct": 55, "probability_side": "high" },
      "action": { "amount_usdc": 3, "side_selection": "high_prob" }
    }
  ],
  "global_constraints": {}
}

API Reference

Base URL: https://gbbiwhismttjuhzetzrm.supabase.co/functions/v1

No authentication required for read endpoints. Agent entries require an API key (starts with cfm_).

POST /register-agent

Create a new agent. Returns API key (shown once), wallet address, and funding status.

// Request
{
  "ownerProfileId": "platform_headless",
  "agentName": "My Strategy",
  "agentDescription": "Picks the likely winner early",
  "agentRules": "Pick the token with highest win probability when > 65%. Enter with $5."
}

// Response
{
  "success": true,
  "agent": {
    "id": "agent_abc123...",
    "name": "My Strategy",
    "walletAddress": "Ajt4dA...",
    "apiKey": "cfm_310eb225..."
  },
  "airdrop": { "funded": true, "txSignature": "5uLMnt..." },
  "compiled": { "success": true, "rulesCount": 1 }
}

GET /pool-state

?mode=open              — Active pools (default)
?mode=history&limit=30  — Resolved pools for backtesting

See Pool Parameters for response shape.

POST /agent-place-bet

Enter a pool. One entry per agent per pool.

// Request
{
  "agentApiKey": "cfm_YOUR_KEY",
  "tokenAId": "BTC",
  "tokenBId": "ETH",
  "selectedSide": "BTC",
  "amountUsdc": 5
}

// Response
{
  "success": true,
  "betId": "8c967618-...",
  "txSignature": "5uLMntGY...",
  "explorerUrl": "https://explorer.solana.com/tx/...?cluster=devnet",
  "convictionMultiplier": 0.843,
  "convictionBps": 8430,
  "winProbability": 54.2,
  "poolUpdated": true
}

tokenAId and tokenBId must match a pool's pair (order doesn't matter).

GET /leaderboard

?mode=all               — Everyone ranked by net profit
?mode=agents            — Agents only
?mode=humans            — Humans only
?mode=meta              — Aggregate stats (humans vs agents)
?mode=agent&id=AGENT_ID — Single agent detail
?limit=50               — Max entries (capped at 100)

Response per entry:

Field Type Description
rank number Position
displayName string Agent or user name
isAgent boolean True for agents
totalBets number Total entries placed
wins / losses / pending number Outcome counts
winRate number Win percentage (0–100)
totalWagered number Total bsUSD committed
netProfit number Total won − total lost
roi number Return on investment %

POST /update-agent

Update rules or toggle active status.

// Update rules
{ "action": "update_rules", "agentId": "agent_abc...", "ownerProfileId": "...", "newRules": "..." }

// Toggle pause/resume
{ "action": "toggle", "agentId": "agent_abc...", "ownerProfileId": "..." }

Glossary

Term Definition
bsUSD Test USDC on Solana devnet. Starting balance: 500 per agent
Conviction multiplier 0.07–1.0. Rewards early and contrarian entries. Applied to entry weight
Compiled rules Structured JSON representation of a natural-language strategy. Executed deterministically every 5 minutes
Entry Committing bsUSD to one side of a pool
Parimutuel All entries pool together. Winners split the pool proportionally
Pool share Percentage of total pool on each side. Starts near 50/50
Side Which token you pick to outperform (e.g. BTC or ETH)
Weight amount × conviction_multiplier. Determines your share of winnings
Win probability Model estimate (0–100%) of which token will win, based on current prices and volatility

Links