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
- User Experience - Markets should resolve quickly enough to be engaging
- Price Movement - Duration must allow meaningful price changes
- Oracle Reliability - Longer durations are more resilient to oracle issues
- Gas Efficiency - Shorter durations mean more markets and more transactions
- Liquidity - Longer durations concentrate liquidity better
- Cadence Simplicity - Duration should align with human time concepts
Duration Analysis
| Duration | Markets/Day | Pros | Cons |
|---|---|---|---|
| 1 minute | 1,440 | Very fast feedback | Noise dominates, high gas |
| 5 minutes | 288 | Fast feedback | Still noisy, fragmented liquidity |
| 15 minutes | 96 | Balanced, memorable cadence | Moderate wait time |
| 1 hour | 24 | Meaningful moves | Slow feedback, long waits |
| 4 hours | 6 | Very meaningful | Too 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
-
Memorable Cadence
- Aligns with quarter-hour boundaries
- Easy to track (":00", ":15", ":30", ":45")
- Natural for scheduling
-
Meaningful Price Movement
- Crypto assets typically move 0.1-1% in 15 minutes
- Enough signal to not be pure noise
- Binary outcomes are meaningful
-
Balanced Engagement
- Fast enough for active trading
- Slow enough to not be overwhelming
- 4 opportunities per hour
-
Reasonable Gas Costs
- 96 market creations/day manageable
- Settlement batching practical
- Crank economics viable
-
Liquidity Concentration
- Each market has 15 minutes to accumulate orders
- Better than 1-minute fragmentation
- Reasonable trading window
-
Oracle Resilience
- 15 minutes provides buffer for oracle issues
- Multiple Pyth updates per epoch
- Snapshot retry window
Negative
-
Fixed Duration
- Cannot adapt to volatility
- Low-volatility periods less interesting
- High-volatility periods might want shorter
-
Alignment Constraints
- Markets start at fixed times
- Cannot start custom-timed markets
- Global coordination required
-
Weekend/Holiday Behavior
- Markets continue even when traditional markets closed
- Lower liquidity during off-hours
- Same cadence regardless of activity
Mitigations
-
Volatility-Adaptive UX
- Show implied volatility to users
- Indicate when markets are "interesting"
- Filter low-activity periods in UI
-
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
| Metric | Target | Rationale |
|---|---|---|
| Average volume per epoch | Growing | Market health |
| Price movement distribution | ~1% stddev | Meaningful outcomes |
| Liquidity depth | Tightening spreads | Market efficiency |
| Settlement latency | < 60s after t_end | User 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, andcreator_pubkeyto support multiple concurrent durations per asset per creator.