Overview
Events are the heart of Opinix Trade. Each event represents a prediction market where you can trade on whether a specific outcome will occur. From cryptocurrency prices to real-world happenings, Opinix offers diverse trading opportunities.
Each event has its own isolated order book with independent price discovery based on market sentiment.
Event structure
Every event on Opinix contains structured data:
interface Event {
id : string ; // Unique identifier
title : string ; // Event description
description ?: string ; // Detailed context
status : EventStatus ; // Current lifecycle state
deadline : Date ; // Trading closes at this time
createdAt : Date ; // When event was created
orderBook ?: OrderBook ; // Associated trading data
}
type EventStatus = "ONGOING" | "CLOSED" | "SETTLED" ;
Event example
{
"id" : "bitcoin-to-be-priced-at-6811470-usdt-or-more-at-0735-pm" ,
"title" : "Bitcoin to be priced at 68,11,470 USDT or more at 07:35 PM" ,
"description" : "Will Bitcoin (BTC) reach or exceed 68,11,470 USDT by 7:35 PM IST today?" ,
"status" : "ONGOING" ,
"deadline" : "2026-03-01T19:35:00Z" ,
"orderBook" : {
"topPriceYes" : 7.50 ,
"topPriceNo" : 2.50
}
}
Event lifecycle
Events progress through distinct stages:
ONGOING - Active trading
Status : Trading is liveDuring this phase:
Users can place YES and NO orders
Order book actively matches trades
WebSocket broadcasts real-time updates
Prices fluctuate based on supply/demand
Duration : From creation until deadline
CLOSED - Trading ended
Status : Awaiting outcome verificationWhen deadline passes:
No new orders accepted
Existing orders are canceled
Locked funds return to available balance
Outcome verification begins
Duration : Minutes to hours after deadline
SETTLED - Outcome determined
Status : Final, payouts distributedAfter verification:
Outcome set to YES or NO
Winning positions pay ₹10 per unit
Losing positions expire worthless
Funds credited to winners’ available balance
Duration : Permanent
The transition from CLOSED to SETTLED requires manual verification by Opinix administrators to ensure accuracy.
Browsing events
Access the events list at /events to see all available markets.
Events page implementation
export default async function EventsPage () {
const events = await getEvents ();
return (
< div className = "min-h-screen p-4" >
< h1 className = "text-3xl font-bold mb-6" > Events </ h1 >
< EventList events = { events } />
</ div >
);
}
Fetching events
Events are retrieved from the database via server actions:
export async function getEvents () {
try {
const events = await prisma . event . findMany ({
where: {
status: "ONGOING" // Show only active events
},
include: {
orderBook: {
select: {
topPriceYes: true ,
topPriceNo: true
}
}
},
orderBy: {
deadline: 'asc' // Soonest deadline first
}
});
return events ;
} catch ( error ) {
console . error ( "Error fetching events:" , error );
return [];
}
}
Event card display
Each event appears as a card showing key information:
interface EventCardProps {
event : Event ;
}
export function EventCard ({ event } : EventCardProps ) {
return (
< Card className = "hover:shadow-lg transition-shadow cursor-pointer"
onClick = {() => router.push( `/events/ ${ event . id } ` )}>
<CardHeader>
<CardTitle className= "text-xl" >
{event.title}
</CardTitle>
</CardHeader>
<CardContent>
<div className= "space-y-2" >
<div className= "flex justify-between" >
<span className= "text-blue-500 font-semibold" >
YES: ₹{event.orderBook?.topPriceYes || 0 }
</ span >
< span className = "text-red-500 font-semibold" >
NO : ₹{event.orderBook?.topPriceNo || 0 }
</ span >
</ div >
< div className = "text-sm text-gray-500" >
Closes : {new Date (event.deadline). toLocaleString ()}
</ div >
< div className = "mt-2" >
< Badge variant = {event. status === "ONGOING" ? "success" : "default" } >
{event. status }
</ Badge >
</ div >
</ div >
</ CardContent >
</ Card >
);
}
Event details page
Clicking an event takes you to its dedicated trading page at /events/[id].
Page structure
export default function EventDetailPage ({
params
} : {
params : { id : string }
}) {
return (
< div className = "min-h-screen p-10" >
< TradePage eventId = {params. id } />
</ div >
);
}
Trade page components
The event detail page includes:
export default function TradePage ({ eventId } : { eventId : string }) {
const [ title , setTitle ] = useState ( "" );
useEffect (() => {
async function fetchInitialData () {
const eventData = await getEventDetails ( eventId );
setTitle ( eventData . title );
}
fetchInitialData ();
}, [ eventId ]);
return (
< div className = "min-h-screen p-10" >
< h1 className = "text-3xl font-bold text-center mb-6 mt-1" >
{ title }
</ h1 >
< div className = "grid grid-cols-1 md:grid-cols-3 gap-4" >
< Orderbook />
< BidCard />
</ div >
< ProbabilityChart />
< Overview />
</ div >
);
}
Orderbook Real-time display of all pending YES and NO orders with price levels and quantities
Bid card Interface to place your YES or NO orders with price and quantity inputs
Probability chart Historical price movements showing how market sentiment has evolved
Overview Detailed event description, rules, and settlement criteria
Event data fetching
Retrieve specific event details:
export async function getEventDetails ( eventId : string ) {
try {
const event = await prisma . event . findUnique ({
where: { id: eventId },
include: {
orderBook: {
include: {
yes: {
orderBy: { price: 'desc' } // Highest price first
},
no: {
orderBy: { price: 'asc' } // Lowest price first
}
}
}
}
});
if ( ! event ) {
throw new Error ( "Event not found" );
}
return event ;
} catch ( error ) {
console . error ( "Error fetching event details:" , error );
throw error ;
}
}
Event categories
Opinix supports multiple event types:
Cryptocurrency
Sports
Politics
Custom events
Price predictions for digital assets Examples:
“Bitcoin to reach $100,000 by end of month”
“Ethereum to be priced above 4,000 USDT at 6 PM”
“Solana market cap to exceed $50B this week”
Characteristics:
High volatility
Frequent price updates
Short-term outcomes (hours to days)
Objective settlement criteria
Outcomes of sporting events Examples:
“India to win the cricket match against Australia”
“Cristiano Ronaldo to score in tonight’s game”
“Lakers to beat Warriors by 10+ points”
Characteristics:
Clear win/loss outcomes
Fixed event times
High user engagement
Publicly verifiable results
Political events and elections Examples:
“Party X to win majority in upcoming election”
“Bill Y to pass parliament this session”
“Candidate Z to lead in opinion polls next week”
Characteristics:
Longer timeframes
Complex settlement criteria
Influenced by news and polls
May require expert verification
User-generated or special markets Examples:
“Weather in Mumbai to exceed 35°C tomorrow”
“New iPhone to launch before December”
“Netflix subscribers to reach 300M this quarter”
Characteristics:
Diverse topics
Varying timeframes
May require data source verification
Creative market opportunities
Real-time event updates
Events receive live updates via WebSocket:
Client-side subscription
useEffect (() => {
const ws = new WebSocket ( 'ws://server-url' );
ws . onopen = () => {
// Subscribe to this event's updates
ws . send ( JSON . stringify ({
eventId: eventId
}));
};
ws . onmessage = ( message ) => {
const data = JSON . parse ( message . data );
// Update order book
setOrderBook ({
yes: data . orderBook . yes ,
no: data . orderBook . no ,
topPriceYes: data . orderBook . topPriceYes ,
topPriceNo: data . orderBook . topPriceNo
});
};
ws . onclose = () => {
console . log ( 'Disconnected from event updates' );
};
return () => ws . close ();
}, [ eventId ]);
Server-side broadcasting
export async function updateOrderBook () {
const onGoingEvents = await prisma . event . findMany ({
where: { status: "ONGOING" },
include: {
orderBook: {
include: { yes: true , no: true }
}
}
});
for ( const event of onGoingEvents ) {
if ( ! event . orderBook ) continue ;
const orderBook = event . orderBook ;
// Simulate market activity (or use real data)
orderBook . yes . forEach (( order : any ) => {
if ( order . price >= orderBook . topPriceYes ) {
const change = Math . floor ( Math . random () * 5 ) - 2 ;
order . quantity = Math . max ( 0 , order . quantity + change );
}
});
// Broadcast to all subscribed clients
WebsocketServer . broadcast ( event . id , {
orderBook: {
yes: orderBook . yes ,
no: orderBook . no ,
topPriceYes: orderBook . topPriceYes ,
topPriceNo: orderBook . topPriceNo
}
});
}
}
Event settlement
When an event’s deadline passes, the settlement process begins:
Automatic closure
At the deadline, a scheduled job: await prisma . event . update ({
where: { id: eventId },
data: { status: "CLOSED" }
});
This stops all trading and cancels unmatched orders.
Outcome verification
Administrators verify the actual outcome:
Check official data sources
Confirm event occurrence
Document evidence
Set outcome in database
Payout calculation
System calculates payouts for all positions: const positions = await prisma . position . findMany ({
where: { eventId , side: outcome }
});
for ( const position of positions ) {
const payout = position . quantity * 10 ;
await prisma . user . update ({
where: { id: position . userId },
data: {
balance: { increment: payout }
}
});
}
Event marked settled
await prisma . event . update ({
where: { id: eventId },
data: {
status: "SETTLED" ,
outcome: outcome // "YES" or "NO"
}
});
Winners receive ₹10 per unit, losers get nothing.
Event creation (Admin)
While not user-facing, here’s how events are created:
export async function createEvent ({
title ,
description ,
deadline
} : {
title : string ;
description ?: string ;
deadline : Date ;
}) {
const event = await prisma . event . create ({
data: {
id: generateEventId ( title ), // URL-friendly ID
title ,
description ,
status: "ONGOING" ,
deadline ,
orderBook: {
create: {
topPriceYes: 5.0 , // Initial price
topPriceNo: 5.0 , // Initial price
yes: { create: [] },
no: { create: [] }
}
}
}
});
return event ;
}
function generateEventId ( title : string ) : string {
return title
. toLowerCase ()
. replace ( / [ ^ a-z0-9 ] + / g , '-' )
. replace ( / ^ - + | - + $ / g , '' );
}
Searching and filtering events
Search and filter functionality is not yet implemented in the UI but can be added.
Potential filters:
interface EventFilters {
status ?: EventStatus [];
category ?: string [];
minVolume ?: number ;
maxDeadline ?: Date ;
searchQuery ?: string ;
}
export async function getFilteredEvents ( filters : EventFilters ) {
return await prisma . event . findMany ({
where: {
status: filters . status ? { in: filters . status } : undefined ,
deadline: filters . maxDeadline ? { lte: filters . maxDeadline } : undefined ,
title: filters . searchQuery ? {
contains: filters . searchQuery ,
mode: 'insensitive'
} : undefined
},
orderBy: { deadline: 'asc' }
});
}
Event metrics
Useful analytics for events:
Trading volume
Unique traders
Order book depth
Price history
Total value traded on the event: const volume = await prisma . trade . aggregate ({
where: { eventId },
_sum: {
amount: true // price * quantity
}
});
Number of distinct users who traded: const traders = await prisma . trade . findMany ({
where: { eventId },
select: { userId: true },
distinct: [ 'userId' ]
});
const uniqueTraders = traders . length ;
Total liquidity at best prices: const depth = {
yesQty: orderBook . yes
. filter ( o => o . price === topPriceYes )
. reduce (( sum , o ) => sum + o . quantity , 0 ),
noQty: orderBook . no
. filter ( o => o . price === topPriceNo )
. reduce (( sum , o ) => sum + o . quantity , 0 )
};
Track how probabilities changed over time: const priceHistory = await prisma . priceSnapshot . findMany ({
where: { eventId },
orderBy: { timestamp: 'asc' },
select: {
timestamp: true ,
yesPrice: true ,
noPrice: true
}
});
Best practices
Read event details Always review the event description and settlement criteria before trading.
Check deadline Ensure you have enough time to react to market movements before the event closes.
Verify sources For data-driven events, confirm the official data source used for settlement.
Manage exposure Don’t over-concentrate in a single event; diversify across multiple markets.
Troubleshooting
Possible causes:
Invalid event ID in URL
Event has been deleted
Database connection issue
Try returning to the events list and selecting again.
Check:
WebSocket connection status (browser console)
Network connectivity
Server status
Refresh the page to reconnect WebSocket.
Verify:
Event status is ONGOING (not CLOSED or SETTLED)
You have sufficient balance
You’re signed in
Check event deadline hasn’t passed.
Settlement taking too long
Settlement requires:
Manual verification by administrators
Confirmation of outcome from official sources
Database updates across all positions
Complex events may take hours to settle. Check back later.
Next steps