graph and bet panel for pseudo numeric

This commit is contained in:
mantikoros 2022-06-27 16:22:20 -05:00
parent a1bdf552c0
commit 0ee6dfae94
8 changed files with 80 additions and 18 deletions

View File

@ -14,6 +14,7 @@ import {
DPMBinaryContract, DPMBinaryContract,
FreeResponseContract, FreeResponseContract,
NumericContract, NumericContract,
PseudoNumericContract,
} from './contract' } from './contract'
import { noFees } from './fees' import { noFees } from './fees'
import { addObjects } from './util/object' import { addObjects } from './util/object'
@ -32,7 +33,7 @@ export type BetInfo = {
export const getNewBinaryCpmmBetInfo = ( export const getNewBinaryCpmmBetInfo = (
outcome: 'YES' | 'NO', outcome: 'YES' | 'NO',
amount: number, amount: number,
contract: CPMMBinaryContract, contract: CPMMBinaryContract | PseudoNumericContract,
loanAmount: number loanAmount: number
) => { ) => {
const { shares, newPool, newP, fees } = calculateCpmmPurchase( const { shares, newPool, newP, fees } = calculateCpmmPurchase(

View File

@ -70,7 +70,10 @@ export const placebet = newEndpoint(['POST'], async (req, auth) => {
if (outcomeType == 'BINARY' && mechanism == 'dpm-2') { if (outcomeType == 'BINARY' && mechanism == 'dpm-2') {
const { outcome } = validate(binarySchema, req.body) const { outcome } = validate(binarySchema, req.body)
return getNewBinaryDpmBetInfo(outcome, amount, contract, loanAmount) return getNewBinaryDpmBetInfo(outcome, amount, contract, loanAmount)
} else if (outcomeType == 'BINARY' && mechanism == 'cpmm-1') { } else if (
(outcomeType == 'BINARY' || outcomeType == 'PSEUDO_NUMERIC') &&
mechanism == 'cpmm-1'
) {
const { outcome } = validate(binarySchema, req.body) const { outcome } = validate(binarySchema, req.body)
return getNewBinaryCpmmBetInfo(outcome, amount, contract, loanAmount) return getNewBinaryCpmmBetInfo(outcome, amount, contract, loanAmount)
} else if (outcomeType == 'FREE_RESPONSE' && mechanism == 'dpm-2') { } else if (outcomeType == 'FREE_RESPONSE' && mechanism == 'dpm-2') {

View File

@ -3,7 +3,11 @@ import React, { useEffect, useState } from 'react'
import { partition, sumBy } from 'lodash' import { partition, sumBy } from 'lodash'
import { useUser } from 'web/hooks/use-user' import { useUser } from 'web/hooks/use-user'
import { BinaryContract, CPMMBinaryContract } from 'common/contract' import {
BinaryContract,
CPMMBinaryContract,
PseudoNumericContract,
} from 'common/contract'
import { Col } from './layout/col' import { Col } from './layout/col'
import { Row } from './layout/row' import { Row } from './layout/row'
import { Spacer } from './layout/spacer' import { Spacer } from './layout/spacer'
@ -190,12 +194,13 @@ export function BetPanelSwitcher(props: {
} }
function BuyPanel(props: { function BuyPanel(props: {
contract: BinaryContract contract: BinaryContract | PseudoNumericContract
user: User | null | undefined user: User | null | undefined
selected?: 'YES' | 'NO' selected?: 'YES' | 'NO'
onBuySuccess?: () => void onBuySuccess?: () => void
}) { }) {
const { contract, user, selected, onBuySuccess } = props const { contract, user, selected, onBuySuccess } = props
const isPseudoNumeric = contract.outcomeType === 'PSEUDO_NUMERIC'
const [betChoice, setBetChoice] = useState<'YES' | 'NO' | undefined>(selected) const [betChoice, setBetChoice] = useState<'YES' | 'NO' | undefined>(selected)
const [betAmount, setBetAmount] = useState<number | undefined>(undefined) const [betAmount, setBetAmount] = useState<number | undefined>(undefined)
@ -302,6 +307,12 @@ function BuyPanel(props: {
: 0) : 0)
)} ${betChoice ?? 'YES'} shares` )} ${betChoice ?? 'YES'} shares`
: undefined : undefined
const format = isPseudoNumeric
? (p: number) =>
Math.round(p * (contract.max - contract.min) + contract.min).toString()
: (p: number) => formatPercent(p)
return ( return (
<> <>
<YesNoSelector <YesNoSelector
@ -309,6 +320,7 @@ function BuyPanel(props: {
btnClassName="flex-1" btnClassName="flex-1"
selected={betChoice} selected={betChoice}
onSelect={(choice) => onBetChoice(choice)} onSelect={(choice) => onBetChoice(choice)}
isPseudoNumeric={isPseudoNumeric}
/> />
<div className="my-3 text-left text-sm text-gray-500">Amount</div> <div className="my-3 text-left text-sm text-gray-500">Amount</div>
<BuyAmountInput <BuyAmountInput
@ -323,11 +335,13 @@ function BuyPanel(props: {
<Col className="mt-3 w-full gap-3"> <Col className="mt-3 w-full gap-3">
<Row className="items-center justify-between text-sm"> <Row className="items-center justify-between text-sm">
<div className="text-gray-500">Probability</div> <div className="text-gray-500">
{isPseudoNumeric ? 'Value' : 'Probability'}
</div>
<div> <div>
{formatPercent(initialProb)} {format(initialProb)}
<span className="mx-2"></span> <span className="mx-2"></span>
{formatPercent(resultProb)} {format(resultProb)}
</div> </div>
</Row> </Row>
@ -340,6 +354,8 @@ function BuyPanel(props: {
<br /> payout if{' '} <br /> payout if{' '}
<BinaryOutcomeLabel outcome={betChoice ?? 'YES'} /> <BinaryOutcomeLabel outcome={betChoice ?? 'YES'} />
</> </>
) : isPseudoNumeric ? (
'Max payout'
) : ( ) : (
<> <>
Payout if <BinaryOutcomeLabel outcome={betChoice ?? 'YES'} /> Payout if <BinaryOutcomeLabel outcome={betChoice ?? 'YES'} />

View File

@ -32,6 +32,7 @@ export const ContractOverview = (props: {
const user = useUser() const user = useUser()
const isCreator = user?.id === creatorId const isCreator = user?.id === creatorId
const isBinary = outcomeType === 'BINARY' const isBinary = outcomeType === 'BINARY'
const isPseudoNumeric = outcomeType === 'PSEUDO_NUMERIC'
return ( return (
<Col className={clsx('mb-6', className)}> <Col className={clsx('mb-6', className)}>
@ -86,7 +87,9 @@ export const ContractOverview = (props: {
/> />
</Col> </Col>
<Spacer h={4} /> <Spacer h={4} />
{isBinary && <ContractProbGraph contract={contract} bets={bets} />}{' '} {(isBinary || isPseudoNumeric) && (
<ContractProbGraph contract={contract} bets={bets} />
)}{' '}
{outcomeType === 'FREE_RESPONSE' && ( {outcomeType === 'FREE_RESPONSE' && (
<AnswersGraph contract={contract} bets={bets} /> <AnswersGraph contract={contract} bets={bets} />
)} )}

View File

@ -5,11 +5,11 @@ import dayjs from 'dayjs'
import { memo } from 'react' import { memo } from 'react'
import { Bet } from 'common/bet' import { Bet } from 'common/bet'
import { getInitialProbability } from 'common/calculate' import { getInitialProbability } from 'common/calculate'
import { BinaryContract } from 'common/contract' import { BinaryContract, PseudoNumericContract } from 'common/contract'
import { useWindowSize } from 'web/hooks/use-window-size' import { useWindowSize } from 'web/hooks/use-window-size'
export const ContractProbGraph = memo(function ContractProbGraph(props: { export const ContractProbGraph = memo(function ContractProbGraph(props: {
contract: BinaryContract contract: BinaryContract | PseudoNumericContract
bets: Bet[] bets: Bet[]
height?: number height?: number
}) { }) {
@ -24,7 +24,13 @@ export const ContractProbGraph = memo(function ContractProbGraph(props: {
contract.createdTime, contract.createdTime,
...bets.map((bet) => bet.createdTime), ...bets.map((bet) => bet.createdTime),
].map((time) => new Date(time)) ].map((time) => new Date(time))
const probs = [startProb, ...bets.map((bet) => bet.probAfter)]
const f =
contract.outcomeType === 'PSEUDO_NUMERIC'
? (p: number) => (p * (contract.max - contract.min) + contract.min) / 100
: (p: number) => p
const probs = [startProb, ...bets.map((bet) => bet.probAfter)].map(f)
const isClosed = !!closeTime && Date.now() > closeTime const isClosed = !!closeTime && Date.now() > closeTime
const latestTime = dayjs( const latestTime = dayjs(
@ -39,7 +45,7 @@ export const ContractProbGraph = memo(function ContractProbGraph(props: {
times.push(latestTime.toDate()) times.push(latestTime.toDate())
probs.push(probs[probs.length - 1]) probs.push(probs[probs.length - 1])
const yTickValues = [0, 25, 50, 75, 100] const yTickValues = [0, 25, 50, 75, 100].map(f)
const { width } = useWindowSize() const { width } = useWindowSize()
@ -80,6 +86,9 @@ export const ContractProbGraph = memo(function ContractProbGraph(props: {
const multiYear = !dayjs(startDate).isSame(latestTime, 'year') const multiYear = !dayjs(startDate).isSame(latestTime, 'year')
const lessThanAWeek = dayjs(startDate).add(8, 'day').isAfter(latestTime) const lessThanAWeek = dayjs(startDate).add(8, 'day').isAfter(latestTime)
const formatter =
contract.outcomeType === 'BINARY' ? formatPercent : formatNumeric
return ( return (
<div <div
className="w-full overflow-visible" className="w-full overflow-visible"
@ -88,11 +97,11 @@ export const ContractProbGraph = memo(function ContractProbGraph(props: {
<ResponsiveLine <ResponsiveLine
data={data} data={data}
yScale={{ min: 0, max: 100, type: 'linear' }} yScale={{ min: 0, max: 100, type: 'linear' }}
yFormat={formatPercent} yFormat={formatter}
gridYValues={yTickValues} gridYValues={yTickValues}
axisLeft={{ axisLeft={{
tickValues: yTickValues, tickValues: yTickValues,
format: formatPercent, format: formatter,
}} }}
xScale={{ xScale={{
type: 'time', type: 'time',
@ -138,6 +147,10 @@ function formatPercent(y: DatumValue) {
return `${Math.round(+y.toString())}%` return `${Math.round(+y.toString())}%`
} }
function formatNumeric(y: DatumValue) {
return `${Math.round(+y.toString())}`
}
function formatTime( function formatTime(
time: number, time: number,
includeYear: boolean, includeYear: boolean,

View File

@ -19,11 +19,15 @@ export function OutcomeLabel(props: {
value?: number value?: number
}) { }) {
const { outcome, contract, truncate, value } = props const { outcome, contract, truncate, value } = props
const {outcomeType} = contract
if (contract.outcomeType === 'BINARY') if (outcomeType === 'PSEUDO_NUMERIC')
return <PseudoNumericOutcomeLabel outcome={outcome as any} />
if (outcomeType === 'BINARY')
return <BinaryOutcomeLabel outcome={outcome as any} /> return <BinaryOutcomeLabel outcome={outcome as any} />
if (contract.outcomeType === 'NUMERIC') if (outcomeType === 'NUMERIC')
return ( return (
<span className="text-blue-500"> <span className="text-blue-500">
{value ?? getValueFromBucket(outcome, contract)} {value ?? getValueFromBucket(outcome, contract)}
@ -49,6 +53,15 @@ export function BinaryOutcomeLabel(props: { outcome: resolution }) {
return <CancelLabel /> return <CancelLabel />
} }
export function PseudoNumericOutcomeLabel(props: { outcome: resolution }) {
const { outcome } = props
if (outcome === 'YES') return <HigherLabel />
if (outcome === 'NO') return <LowerLabel />
if (outcome === 'MKT') return <ProbLabel />
return <CancelLabel />
}
export function BinaryContractOutcomeLabel(props: { export function BinaryContractOutcomeLabel(props: {
contract: BinaryContract contract: BinaryContract
resolution: resolution resolution: resolution
@ -98,6 +111,16 @@ export function YesLabel() {
return <span className="text-primary">YES</span> return <span className="text-primary">YES</span>
} }
export function HigherLabel() {
return <span className="text-primary">HIGH</span>
}
export function LowerLabel() {
return <span className="text-red-400">LOW</span>
}
export function NoLabel() { export function NoLabel() {
return <span className="text-red-400">NO</span> return <span className="text-red-400">NO</span>
} }

View File

@ -12,6 +12,7 @@ export function YesNoSelector(props: {
btnClassName?: string btnClassName?: string
replaceYesButton?: React.ReactNode replaceYesButton?: React.ReactNode
replaceNoButton?: React.ReactNode replaceNoButton?: React.ReactNode
isPseudoNumeric?: boolean
}) { }) {
const { const {
selected, selected,
@ -20,6 +21,7 @@ export function YesNoSelector(props: {
btnClassName, btnClassName,
replaceNoButton, replaceNoButton,
replaceYesButton, replaceYesButton,
isPseudoNumeric,
} = props } = props
const commonClassNames = const commonClassNames =
@ -41,7 +43,7 @@ export function YesNoSelector(props: {
)} )}
onClick={() => onSelect('YES')} onClick={() => onSelect('YES')}
> >
Bet YES {isPseudoNumeric ? 'Higher' : 'Bet YES'}
</button> </button>
)} )}
{replaceNoButton ? ( {replaceNoButton ? (
@ -58,7 +60,7 @@ export function YesNoSelector(props: {
)} )}
onClick={() => onSelect('NO')} onClick={() => onSelect('NO')}
> >
Bet NO {isPseudoNumeric ? 'Lower' : 'Bet NO'}
</button> </button>
)} )}
</Row> </Row>

View File

@ -199,6 +199,7 @@ export function ContractPageContent(
)} )}
<ContractOverview contract={contract} bets={bets} /> <ContractOverview contract={contract} bets={bets} />
{isNumeric && ( {isNumeric && (
<AlertBox <AlertBox
title="Warning" title="Warning"