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,
FreeResponseContract,
NumericContract,
PseudoNumericContract,
} from './contract'
import { noFees } from './fees'
import { addObjects } from './util/object'
@ -32,7 +33,7 @@ export type BetInfo = {
export const getNewBinaryCpmmBetInfo = (
outcome: 'YES' | 'NO',
amount: number,
contract: CPMMBinaryContract,
contract: CPMMBinaryContract | PseudoNumericContract,
loanAmount: number
) => {
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') {
const { outcome } = validate(binarySchema, req.body)
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)
return getNewBinaryCpmmBetInfo(outcome, amount, contract, loanAmount)
} 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 { 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 { Row } from './layout/row'
import { Spacer } from './layout/spacer'
@ -190,12 +194,13 @@ export function BetPanelSwitcher(props: {
}
function BuyPanel(props: {
contract: BinaryContract
contract: BinaryContract | PseudoNumericContract
user: User | null | undefined
selected?: 'YES' | 'NO'
onBuySuccess?: () => void
}) {
const { contract, user, selected, onBuySuccess } = props
const isPseudoNumeric = contract.outcomeType === 'PSEUDO_NUMERIC'
const [betChoice, setBetChoice] = useState<'YES' | 'NO' | undefined>(selected)
const [betAmount, setBetAmount] = useState<number | undefined>(undefined)
@ -302,6 +307,12 @@ function BuyPanel(props: {
: 0)
)} ${betChoice ?? 'YES'} shares`
: undefined
const format = isPseudoNumeric
? (p: number) =>
Math.round(p * (contract.max - contract.min) + contract.min).toString()
: (p: number) => formatPercent(p)
return (
<>
<YesNoSelector
@ -309,6 +320,7 @@ function BuyPanel(props: {
btnClassName="flex-1"
selected={betChoice}
onSelect={(choice) => onBetChoice(choice)}
isPseudoNumeric={isPseudoNumeric}
/>
<div className="my-3 text-left text-sm text-gray-500">Amount</div>
<BuyAmountInput
@ -323,11 +335,13 @@ function BuyPanel(props: {
<Col className="mt-3 w-full gap-3">
<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>
{formatPercent(initialProb)}
{format(initialProb)}
<span className="mx-2"></span>
{formatPercent(resultProb)}
{format(resultProb)}
</div>
</Row>
@ -340,6 +354,8 @@ function BuyPanel(props: {
<br /> payout if{' '}
<BinaryOutcomeLabel outcome={betChoice ?? 'YES'} />
</>
) : isPseudoNumeric ? (
'Max payout'
) : (
<>
Payout if <BinaryOutcomeLabel outcome={betChoice ?? 'YES'} />

View File

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

View File

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

View File

@ -19,11 +19,15 @@ export function OutcomeLabel(props: {
value?: number
}) {
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} />
if (contract.outcomeType === 'NUMERIC')
if (outcomeType === 'NUMERIC')
return (
<span className="text-blue-500">
{value ?? getValueFromBucket(outcome, contract)}
@ -49,6 +53,15 @@ export function BinaryOutcomeLabel(props: { outcome: resolution }) {
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: {
contract: BinaryContract
resolution: resolution
@ -98,6 +111,16 @@ export function YesLabel() {
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() {
return <span className="text-red-400">NO</span>
}

View File

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

View File

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