Skip to main content

ADR-003: 15-Minute Market Epochs

Status

Accepted (amended — see Addendum)

Context

Seesaw creates continuous binary prediction markets. A key design decision is the epoch duration - how long each market runs before resolution.

Considerations

  1. User Experience - Markets should resolve quickly enough to be engaging
  2. Price Movement - Duration must allow meaningful price changes
  3. Oracle Reliability - Longer durations are more resilient to oracle issues
  4. Gas Efficiency - Shorter durations mean more markets and more transactions
  5. Liquidity - Longer durations concentrate liquidity better
  6. Cadence Simplicity - Duration should align with human time concepts

Duration Analysis

DurationMarkets/DayProsCons
1 minute1,440Very fast feedbackNoise dominates, high gas
5 minutes288Fast feedbackStill noisy, fragmented liquidity
15 minutes96Balanced, memorable cadenceModerate wait time
1 hour24Meaningful movesSlow feedback, long waits
4 hours6Very meaningfulToo slow for engagement

Decision

Use 15-minute epochs (900 seconds) as the standard market duration.

Market ID Calculation

const EPOCH_DURATION = 900; // seconds

function getMarketId(timestamp: number): bigint {
  return BigInt(Math.floor(timestamp / EPOCH_DURATION));
}

function getMarketTimes(marketId: bigint): { tStart: number; tEnd: number } {
  const tStart = Number(marketId) * EPOCH_DURATION;
  const tEnd = tStart + EPOCH_DURATION;
  return { tStart, tEnd };
}

Daily Cadence

96 markets per day
4 markets per hour
1 market every 15 minutes

Starting at 00:00:00 UTC:
  Market 0: 00:00 - 00:15
  Market 1: 00:15 - 00:30
  Market 2: 00:30 - 00:45
  Market 3: 00:45 - 01:00
  ...
  Market 95: 23:45 - 00:00

Consequences

Positive

  1. Memorable Cadence

    • Aligns with quarter-hour boundaries
    • Easy to track (":00", ":15", ":30", ":45")
    • Natural for scheduling
  2. Meaningful Price Movement

    • Crypto assets typically move 0.1-1% in 15 minutes
    • Enough signal to not be pure noise
    • Binary outcomes are meaningful
  3. Balanced Engagement

    • Fast enough for active trading
    • Slow enough to not be overwhelming
    • 4 opportunities per hour
  4. Reasonable Gas Costs

    • 96 market creations/day manageable
    • Settlement batching practical
    • Crank economics viable
  5. Liquidity Concentration

    • Each market has 15 minutes to accumulate orders
    • Better than 1-minute fragmentation
    • Reasonable trading window
  6. Oracle Resilience

    • 15 minutes provides buffer for oracle issues
    • Multiple Pyth updates per epoch
    • Snapshot retry window

Negative

  1. Fixed Duration

    • Cannot adapt to volatility
    • Low-volatility periods less interesting
    • High-volatility periods might want shorter
  2. Alignment Constraints

    • Markets start at fixed times
    • Cannot start custom-timed markets
    • Global coordination required
  3. Weekend/Holiday Behavior

    • Markets continue even when traditional markets closed
    • Lower liquidity during off-hours
    • Same cadence regardless of activity

Mitigations

  1. Volatility-Adaptive UX

    • Show implied volatility to users
    • Indicate when markets are "interesting"
    • Filter low-activity periods in UI
  2. Future Extensions

    • Could add 5-minute and 1-hour variants later
    • Market types could be parameterized
    • Not a permanent constraint

Alternatives Considered

Alternative 1: 5-Minute Epochs

Shorter duration for faster feedback.

Rejected because:

  • Too much noise relative to signal
  • 288 markets/day strains infrastructure
  • Fragmented liquidity
  • Higher gas costs

Alternative 2: 1-Hour Epochs

Longer duration for more meaningful movements.

Rejected because:

  • Too slow for engagement
  • Users lose interest waiting
  • Only 24 markets/day limits opportunities
  • Worse capital efficiency

Alternative 3: Variable Duration

Let market creators choose duration.

Rejected because:

  • Fragments liquidity across durations
  • Complex market discovery
  • Harder to automate cranking
  • Inconsistent user experience

Alternative 4: Volatility-Adaptive Duration

Automatically adjust based on recent volatility.

Rejected because:

  • Unpredictable schedule
  • Complex implementation
  • Manipulation concerns
  • Harder to communicate to users

Alternative 5: Continuous Markets (No Epochs)

Single market per asset that never resolves.

Rejected because:

  • No settlement events
  • Infinite duration means infinite risk
  • No clear "win/lose" moments
  • Fundamentally different product

Implementation Notes

Epoch Boundaries

pub fn calculate_epoch_boundaries(market_id: u64) -> (i64, i64) {
    const EPOCH_DURATION: i64 = 900;

    let t_start = (market_id as i64) * EPOCH_DURATION;
    let t_end = t_start + EPOCH_DURATION;

    (t_start, t_end)
}

pub fn get_current_market_id(timestamp: i64) -> u64 {
    const EPOCH_DURATION: i64 = 900;
    (timestamp / EPOCH_DURATION) as u64
}

Timing Validation

pub fn validate_snapshot_timing(
    market: &MarketAccount,
    instruction: SnapshotType,
    clock: &Clock,
) -> Result<()> {
    match instruction {
        SnapshotType::Start => {
            require!(
                clock.unix_timestamp >= market.t_start,
                Error::EpochNotStarted
            );
        }
        SnapshotType::End => {
            require!(
                clock.unix_timestamp >= market.t_end,
                Error::EpochNotEnded
            );
        }
    }
    Ok(())
}

Trading Window

pub fn is_trading_allowed(
    market: &MarketAccount,
    clock: &Clock,
) -> bool {
    // Trading allowed after start snapshot, before end
    market.start_price != 0 && clock.unix_timestamp < market.t_end
}

Metrics to Monitor

MetricTargetRationale
Average volume per epochGrowingMarket health
Price movement distribution~1% stddevMeaningful outcomes
Liquidity depthTightening spreadsMarket efficiency
Settlement latency< 60s after t_endUser experience

References

  • SPEC.md - Protocol specification
  • AUTOMATION.md - Market cadence automation
  • Academic research on prediction market duration

Changelog

  • 2026-01: Initial decision
  • 2026-02: Amended — configurable durations (60s–604800s) added. 15-minute remains the default. Market PDA seeds now include pyth_feed_id, duration_seconds, and creator_pubkey to support multiple concurrent durations per asset per creator.