log scale

This commit is contained in:
mantikoros 2022-07-01 13:02:08 -04:00
parent 1afe62296e
commit 543b9960d1
9 changed files with 101 additions and 43 deletions

View File

@ -1,10 +0,0 @@
import { PseudoNumericContract } from './contract'
export function formatNumericProbability(
p: number,
contract: PseudoNumericContract
) {
const { min, max } = contract
const value = p * (max - min) + min
return Math.round(value).toString()
}

45
common/pseudo-numeric.ts Normal file
View File

@ -0,0 +1,45 @@
import { BinaryContract, PseudoNumericContract } from './contract'
import { formatLargeNumber, formatPercent } from './util/format'
export function formatNumericProbability(
p: number,
contract: PseudoNumericContract
) {
const value = getMappedValue(contract)(p)
return formatLargeNumber(value)
}
export const getMappedValue =
(contract: PseudoNumericContract | BinaryContract) => (p: number) => {
if (contract.outcomeType === 'BINARY') return p
const { min, max, isLogScale } = contract
if (isLogScale) {
const logValue = p * Math.log10(max - min)
return 10 ** logValue + min
}
return p * (max - min) + min
}
export const getFormattedMappedValue =
(contract: PseudoNumericContract | BinaryContract) => (p: number) => {
if (contract.outcomeType === 'BINARY') return formatPercent(p)
const value = getMappedValue(contract)(p)
return formatLargeNumber(value)
}
export const getPseudoProbability = (
value: number,
min: number,
max: number,
isLogScale = false
) => {
if (isLogScale) {
return Math.log10(value - min) / Math.log10(max - min)
}
return (value - min) / (max - min)
}

View File

@ -28,6 +28,7 @@ import { getNewContract } from '../../common/new-contract'
import { NUMERIC_BUCKET_COUNT } from '../../common/numeric-constants' import { NUMERIC_BUCKET_COUNT } from '../../common/numeric-constants'
import { User } from '../../common/user' import { User } from '../../common/user'
import { Group, MAX_ID_LENGTH } from '../../common/group' import { Group, MAX_ID_LENGTH } from '../../common/group'
import { getPseudoProbability } from '../../common/pseudo-numeric'
const bodySchema = z.object({ const bodySchema = z.object({
question: z.string().min(1).max(MAX_QUESTION_LENGTH), question: z.string().min(1).max(MAX_QUESTION_LENGTH),
@ -67,7 +68,7 @@ export const createmarket = newEndpoint(['POST'], async (req, auth) => {
if (max - min <= 0.01 || initialValue < min || initialValue > max) if (max - min <= 0.01 || initialValue < min || initialValue > max)
throw new APIError(400, 'Invalid range.') throw new APIError(400, 'Invalid range.')
initialProb = ((initialValue - min) / (max - min)) * 100 initialProb = getPseudoProbability(initialValue, min, max, isLogScale) * 100
} }
if (outcomeType === 'BINARY') { if (outcomeType === 'BINARY') {
;({ initialProb } = validate(binarySchema, req.body)) ;({ initialProb } = validate(binarySchema, req.body))

View File

@ -6,9 +6,13 @@ import { Comment } from '../../common/comment'
import { Contract } from '../../common/contract' import { Contract } from '../../common/contract'
import { DPM_CREATOR_FEE } from '../../common/fees' import { DPM_CREATOR_FEE } from '../../common/fees'
import { PrivateUser, User } from '../../common/user' import { PrivateUser, User } from '../../common/user'
import { formatMoney, formatPercent } from '../../common/util/format' import {
formatLargeNumber,
formatMoney,
formatPercent,
} from '../../common/util/format'
import { getValueFromBucket } from '../../common/calculate-dpm' import { getValueFromBucket } from '../../common/calculate-dpm'
import { formatNumericProbability } from '../../common/numeric' import { formatNumericProbability } from '../../common/pseudo-numeric'
import { sendTemplateEmail } from './send-email' import { sendTemplateEmail } from './send-email'
import { getPrivateUser, getUser } from './utils' import { getPrivateUser, getUser } from './utils'
@ -103,13 +107,14 @@ const toDisplayResolution = (
} }
if (contract.outcomeType === 'PSEUDO_NUMERIC') { if (contract.outcomeType === 'PSEUDO_NUMERIC') {
return ( const { resolutionValue } = contract
contract.resolutionValue?.toString() ??
formatNumericProbability( return resolutionValue
resolutionProbability ?? getProbability(contract), ? formatLargeNumber(resolutionValue)
contract : formatNumericProbability(
) resolutionProbability ?? getProbability(contract),
) contract
)
} }
if (resolution === 'MKT' && resolutions) return 'MULTI' if (resolution === 'MKT' && resolutions) return 'MULTI'

View File

@ -39,6 +39,7 @@ import {
getCpmmProbability, getCpmmProbability,
getCpmmLiquidityFee, getCpmmLiquidityFee,
} from 'common/calculate-cpmm' } from 'common/calculate-cpmm'
import { getFormattedMappedValue } from 'common/pseudo-numeric'
import { SellRow } from './sell-row' import { SellRow } from './sell-row'
import { useSaveShares } from './use-save-shares' import { useSaveShares } from './use-save-shares'
import { SignUpPrompt } from './sign-up-prompt' import { SignUpPrompt } from './sign-up-prompt'
@ -314,10 +315,7 @@ function BuyPanel(props: {
)} ${betChoice ?? 'YES'} shares` )} ${betChoice ?? 'YES'} shares`
: undefined : undefined
const format = isPseudoNumeric const format = getFormattedMappedValue(contract)
? (p: number) =>
Math.round(p * (contract.max - contract.min) + contract.min).toString()
: (p: number) => formatPercent(p)
return ( return (
<> <>
@ -512,10 +510,7 @@ export function SellPanel(props: {
const { outcomeType } = contract const { outcomeType } = contract
const isPseudoNumeric = outcomeType === 'PSEUDO_NUMERIC' const isPseudoNumeric = outcomeType === 'PSEUDO_NUMERIC'
const format = isPseudoNumeric const format = getFormattedMappedValue(contract)
? (p: number) =>
Math.round(p * (contract.max - contract.min) + contract.min).toString()
: (p: number) => formatPercent(p)
return ( return (
<> <>

View File

@ -29,7 +29,7 @@ import { useContractWithPreload } from 'web/hooks/use-contract'
import { useUser } from 'web/hooks/use-user' import { useUser } from 'web/hooks/use-user'
import { track } from '@amplitude/analytics-browser' import { track } from '@amplitude/analytics-browser'
import { trackCallback } from 'web/lib/service/analytics' import { trackCallback } from 'web/lib/service/analytics'
import { formatNumericProbability } from 'common/numeric' import { formatNumericProbability } from 'common/pseudo-numeric'
export function ContractCard(props: { export function ContractCard(props: {
contract: Contract contract: Contract
@ -283,7 +283,9 @@ export function NumericResolutionOrExpectation(props: {
{resolution === 'CANCEL' ? ( {resolution === 'CANCEL' ? (
<CancelLabel /> <CancelLabel />
) : ( ) : (
<div className="text-blue-400">{resolutionValue}</div> <div className="text-blue-400">
{formatLargeNumber(resolutionValue)}
</div>
)} )}
</> </>
) : ( ) : (
@ -316,8 +318,12 @@ export function PseudoNumericResolutionOrExpectation(props: {
<CancelLabel /> <CancelLabel />
) : ( ) : (
<div className="text-blue-400"> <div className="text-blue-400">
{resolutionValue ?? {resolutionValue
formatNumericProbability(resolutionProbability ?? 0, contract)} ? formatLargeNumber(resolutionValue)
: formatNumericProbability(
resolutionProbability ?? 0,
contract
)}
</div> </div>
)} )}
</> </>

View File

@ -7,6 +7,7 @@ import { Bet } from 'common/bet'
import { getInitialProbability } from 'common/calculate' import { getInitialProbability } from 'common/calculate'
import { BinaryContract, PseudoNumericContract } 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'
import { getMappedValue } from 'common/pseudo-numeric'
export const ContractProbGraph = memo(function ContractProbGraph(props: { export const ContractProbGraph = memo(function ContractProbGraph(props: {
contract: BinaryContract | PseudoNumericContract contract: BinaryContract | PseudoNumericContract
@ -26,10 +27,7 @@ export const ContractProbGraph = memo(function ContractProbGraph(props: {
...bets.map((bet) => bet.createdTime), ...bets.map((bet) => bet.createdTime),
].map((time) => new Date(time)) ].map((time) => new Date(time))
const f = const f = getMappedValue(contract)
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 probs = [startProb, ...bets.map((bet) => bet.probAfter)].map(f)
@ -46,9 +44,11 @@ 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 quartiles = [0, 25, 50, 75, 100]
const yTickValues = isBinary const yTickValues = isBinary
? [0, 25, 50, 75, 100] ? quartiles
: [0, 0.25, 0.5, 0.75, 1].map(f).map((x) => x * 100) : quartiles.map((x) => x / 100).map(f)
const { width } = useWindowSize() const { width } = useWindowSize()
@ -64,9 +64,12 @@ export const ContractProbGraph = memo(function ContractProbGraph(props: {
const totalPoints = width ? (width > 800 ? 300 : 50) : 1 const totalPoints = width ? (width > 800 ? 300 : 50) : 1
const timeStep: number = latestTime.diff(startDate, 'ms') / totalPoints const timeStep: number = latestTime.diff(startDate, 'ms') / totalPoints
const points: { x: Date; y: number }[] = [] const points: { x: Date; y: number }[] = []
const s = isBinary ? 100 : 1
for (let i = 0; i < times.length - 1; i++) { for (let i = 0; i < times.length - 1; i++) {
points[points.length] = { x: times[i], y: probs[i] * 100 } points[points.length] = { x: times[i], y: s * probs[i] }
const numPoints: number = Math.floor( const numPoints: number = Math.floor(
dayjs(times[i + 1]).diff(dayjs(times[i]), 'ms') / timeStep dayjs(times[i + 1]).diff(dayjs(times[i]), 'ms') / timeStep
) )
@ -78,7 +81,7 @@ export const ContractProbGraph = memo(function ContractProbGraph(props: {
x: dayjs(times[i]) x: dayjs(times[i])
.add(thisTimeStep * n, 'ms') .add(thisTimeStep * n, 'ms')
.toDate(), .toDate(),
y: probs[i] * 100, y: s * probs[i],
} }
} }
} }
@ -103,7 +106,11 @@ export const ContractProbGraph = memo(function ContractProbGraph(props: {
yScale={ yScale={
isBinary isBinary
? { min: 0, max: 100, type: 'linear' } ? { min: 0, max: 100, type: 'linear' }
: { min: contract.min, max: contract.max, type: 'linear' } : {
min: contract.min,
max: contract.max,
type: contract.isLogScale ? 'log' : 'linear',
}
} }
yFormat={formatter} yFormat={formatter}
gridYValues={yTickValues} gridYValues={yTickValues}

View File

@ -26,7 +26,7 @@ import { useSaveShares } from '../use-save-shares'
import { sellShares } from 'web/lib/firebase/api-call' import { sellShares } from 'web/lib/firebase/api-call'
import { calculateCpmmSale, getCpmmProbability } from 'common/calculate-cpmm' import { calculateCpmmSale, getCpmmProbability } from 'common/calculate-cpmm'
import { track } from 'web/lib/service/analytics' import { track } from 'web/lib/service/analytics'
import { formatNumericProbability } from 'common/numeric' import { formatNumericProbability } from 'common/pseudo-numeric'
const BET_SIZE = 10 const BET_SIZE = 10

View File

@ -9,6 +9,7 @@ import { ResolveConfirmationButton } from './confirmation-button'
import { resolveMarket } from 'web/lib/firebase/fn-call' import { resolveMarket } from 'web/lib/firebase/fn-call'
import { NumericContract, PseudoNumericContract } from 'common/contract' import { NumericContract, PseudoNumericContract } from 'common/contract'
import { BucketInput } from './bucket-input' import { BucketInput } from './bucket-input'
import { getPseudoProbability } from 'common/pseudo-numeric'
export function NumericResolutionPanel(props: { export function NumericResolutionPanel(props: {
creator: User creator: User
@ -44,7 +45,15 @@ export function NumericResolutionPanel(props: {
setIsSubmitting(true) setIsSubmitting(true)
const boundedValue = Math.max(Math.min(max, value ?? 0), min) const boundedValue = Math.max(Math.min(max, value ?? 0), min)
const probabilityInt = ((boundedValue - min) / (max - min)) * 100
const probabilityInt =
100 *
getPseudoProbability(
boundedValue,
min,
max,
outcomeType === 'PSEUDO_NUMERIC' && contract.isLogScale
)
const result = await resolveMarket({ const result = await resolveMarket({
outcome: finalOutcome, outcome: finalOutcome,