This commit is contained in:
		
						commit
						544d55bb93
					
				|  | @ -1,7 +1,12 @@ | |||
| import { last, sortBy, sum, sumBy, uniq } from 'lodash' | ||||
| import { calculatePayout } from './calculate' | ||||
| import { Dictionary, groupBy, last, sortBy, sum, sumBy, uniq } from 'lodash' | ||||
| import { calculatePayout, getContractBetMetrics } from './calculate' | ||||
| import { Bet, LimitBet } from './bet' | ||||
| import { Contract, CPMMContract, DPMContract } from './contract' | ||||
| import { | ||||
|   Contract, | ||||
|   CPMMBinaryContract, | ||||
|   CPMMContract, | ||||
|   DPMContract, | ||||
| } from './contract' | ||||
| import { PortfolioMetrics, User } from './user' | ||||
| import { DAY_MS } from './util/time' | ||||
| import { getBinaryCpmmBetInfo, getNewMultiBetInfo } from './new-bet' | ||||
|  | @ -35,8 +40,7 @@ export const computeInvestmentValueCustomProb = ( | |||
| 
 | ||||
|     const betP = outcome === 'YES' ? p : 1 - p | ||||
| 
 | ||||
|     const payout = betP * shares | ||||
|     const value = payout - (bet.loanAmount ?? 0) | ||||
|     const value = betP * shares | ||||
|     if (isNaN(value)) return 0 | ||||
|     return value | ||||
|   }) | ||||
|  | @ -246,3 +250,71 @@ export const calculateNewProfit = ( | |||
| 
 | ||||
|   return newProfit | ||||
| } | ||||
| 
 | ||||
| export const calculateMetricsByContract = ( | ||||
|   bets: Bet[], | ||||
|   contractsById: Dictionary<Contract> | ||||
| ) => { | ||||
|   const betsByContract = groupBy(bets, (bet) => bet.contractId) | ||||
|   const unresolvedContracts = Object.keys(betsByContract) | ||||
|     .map((cid) => contractsById[cid]) | ||||
|     .filter((c) => c && !c.isResolved) | ||||
| 
 | ||||
|   return unresolvedContracts.map((c) => { | ||||
|     const bets = betsByContract[c.id] ?? [] | ||||
|     const current = getContractBetMetrics(c, bets) | ||||
| 
 | ||||
|     let periodMetrics | ||||
|     if (c.mechanism === 'cpmm-1' && c.outcomeType === 'BINARY') { | ||||
|       const periods = ['day', 'week', 'month'] as const | ||||
|       periodMetrics = Object.fromEntries( | ||||
|         periods.map((period) => [ | ||||
|           period, | ||||
|           calculatePeriodProfit(c, bets, period), | ||||
|         ]) | ||||
|       ) | ||||
|     } | ||||
| 
 | ||||
|     return { | ||||
|       contractId: c.id, | ||||
|       ...current, | ||||
|       from: periodMetrics, | ||||
|     } | ||||
|   }) | ||||
| } | ||||
| 
 | ||||
| const calculatePeriodProfit = ( | ||||
|   contract: CPMMBinaryContract, | ||||
|   bets: Bet[], | ||||
|   period: 'day' | 'week' | 'month' | ||||
| ) => { | ||||
|   const days = period === 'day' ? 1 : period === 'week' ? 7 : 30 | ||||
|   const fromTime = Date.now() - days * DAY_MS | ||||
|   const previousBets = bets.filter((b) => b.createdTime < fromTime) | ||||
| 
 | ||||
|   const prevProb = contract.prob - contract.probChanges[period] | ||||
|   const prob = contract.resolutionProbability | ||||
|     ? contract.resolutionProbability | ||||
|     : contract.prob | ||||
| 
 | ||||
|   const previousBetsValue = computeInvestmentValueCustomProb( | ||||
|     previousBets, | ||||
|     contract, | ||||
|     prevProb | ||||
|   ) | ||||
|   const currentBetsValue = computeInvestmentValueCustomProb( | ||||
|     previousBets, | ||||
|     contract, | ||||
|     prob | ||||
|   ) | ||||
|   const profit = currentBetsValue - previousBetsValue | ||||
|   const profitPercent = | ||||
|     previousBetsValue === 0 ? 0 : 100 * (profit / previousBetsValue) | ||||
| 
 | ||||
|   return { | ||||
|     profit, | ||||
|     profitPercent, | ||||
|     prevValue: previousBetsValue, | ||||
|     value: currentBetsValue, | ||||
|   } | ||||
| } | ||||
|  |  | |||
|  | @ -1,6 +1,6 @@ | |||
| import * as functions from 'firebase-functions' | ||||
| import * as admin from 'firebase-admin' | ||||
| import { groupBy, isEmpty, keyBy, last, sortBy } from 'lodash' | ||||
| import { groupBy, keyBy, last, sortBy } from 'lodash' | ||||
| import fetch from 'node-fetch' | ||||
| 
 | ||||
| import { getValues, log, logMemory, writeAsync } from './utils' | ||||
|  | @ -15,6 +15,7 @@ import { | |||
|   calculateNewPortfolioMetrics, | ||||
|   calculateNewProfit, | ||||
|   calculateProbChanges, | ||||
|   calculateMetricsByContract, | ||||
|   computeElasticity, | ||||
|   computeVolume, | ||||
| } from '../../common/calculate-metrics' | ||||
|  | @ -23,6 +24,7 @@ import { Group } from '../../common/group' | |||
| import { batchedWaitAll } from '../../common/util/promise' | ||||
| import { newEndpointNoAuth } from './api' | ||||
| import { getFunctionUrl } from '../../common/api' | ||||
| import { filterDefined } from '../../common/util/array' | ||||
| 
 | ||||
| const firestore = admin.firestore() | ||||
| export const scheduleUpdateMetrics = functions.pubsub | ||||
|  | @ -159,6 +161,12 @@ export async function updateMetricsCore() { | |||
|       lastPortfolio.investmentValue !== newPortfolio.investmentValue | ||||
| 
 | ||||
|     const newProfit = calculateNewProfit(portfolioHistory, newPortfolio) | ||||
| 
 | ||||
|     const metricsByContract = calculateMetricsByContract( | ||||
|       currentBets, | ||||
|       contractsById | ||||
|     ) | ||||
| 
 | ||||
|     const contractRatios = userContracts | ||||
|       .map((contract) => { | ||||
|         if ( | ||||
|  | @ -189,6 +197,7 @@ export async function updateMetricsCore() { | |||
|       newProfit, | ||||
|       didPortfolioChange, | ||||
|       newFractionResolvedCorrectly, | ||||
|       metricsByContract, | ||||
|     } | ||||
|   }) | ||||
| 
 | ||||
|  | @ -204,17 +213,9 @@ export async function updateMetricsCore() { | |||
|   const nextLoanByUser = keyBy(userPayouts, (payout) => payout.user.id) | ||||
| 
 | ||||
|   const userUpdates = userMetrics.map( | ||||
|     ({ | ||||
|       user, | ||||
|       newCreatorVolume, | ||||
|       newPortfolio, | ||||
|       newProfit, | ||||
|       didPortfolioChange, | ||||
|       newFractionResolvedCorrectly, | ||||
|     }) => { | ||||
|     ({ user, newCreatorVolume, newProfit, newFractionResolvedCorrectly }) => { | ||||
|       const nextLoanCached = nextLoanByUser[user.id]?.payout ?? 0 | ||||
|       return { | ||||
|         fieldUpdates: { | ||||
|         doc: firestore.collection('users').doc(user.id), | ||||
|         fields: { | ||||
|           creatorVolumeCached: newCreatorVolume, | ||||
|  | @ -222,45 +223,51 @@ export async function updateMetricsCore() { | |||
|           nextLoanCached, | ||||
|           fractionResolvedCorrectly: newFractionResolvedCorrectly, | ||||
|         }, | ||||
|         }, | ||||
|       } | ||||
|     } | ||||
|   ) | ||||
|   await writeAsync(firestore, userUpdates) | ||||
| 
 | ||||
|         subcollectionUpdates: { | ||||
|   const portfolioHistoryUpdates = filterDefined( | ||||
|     userMetrics.map(({ user, newPortfolio, didPortfolioChange }) => { | ||||
|       return didPortfolioChange | ||||
|         ? { | ||||
|             doc: firestore | ||||
|               .collection('users') | ||||
|               .doc(user.id) | ||||
|               .collection('portfolioHistory') | ||||
|               .doc(), | ||||
|           fields: didPortfolioChange ? newPortfolio : {}, | ||||
|         }, | ||||
|             fields: newPortfolio, | ||||
|           } | ||||
|         : null | ||||
|     }) | ||||
|   ) | ||||
|   await writeAsync(firestore, portfolioHistoryUpdates, 'set') | ||||
| 
 | ||||
|   const contractMetricsUpdates = userMetrics.flatMap( | ||||
|     ({ user, metricsByContract }) => { | ||||
|       const collection = firestore | ||||
|         .collection('users') | ||||
|         .doc(user.id) | ||||
|         .collection('contract-metrics') | ||||
|       return metricsByContract.map((metrics) => ({ | ||||
|         doc: collection.doc(metrics.contractId), | ||||
|         fields: metrics, | ||||
|       })) | ||||
|     } | ||||
|   ) | ||||
|   await writeAsync( | ||||
|     firestore, | ||||
|     userUpdates.map((u) => u.fieldUpdates) | ||||
|   ) | ||||
|   await writeAsync( | ||||
|     firestore, | ||||
|     userUpdates | ||||
|       .filter((u) => !isEmpty(u.subcollectionUpdates.fields)) | ||||
|       .map((u) => u.subcollectionUpdates), | ||||
|     'set' | ||||
|   ) | ||||
| 
 | ||||
|   await writeAsync(firestore, contractMetricsUpdates, 'set') | ||||
| 
 | ||||
|   log(`Updated metrics for ${users.length} users.`) | ||||
| 
 | ||||
|   try { | ||||
|     const groupUpdates = groups.map((group, index) => { | ||||
|       const groupContractIds = contractsByGroup[index] as GroupContractDoc[] | ||||
|       const groupContracts = groupContractIds | ||||
|         .map((e) => contractsById[e.contractId]) | ||||
|         .filter((e) => e !== undefined) as Contract[] | ||||
|       const bets = groupContracts.map((e) => { | ||||
|         if (e != null && e.id in betsByContract) { | ||||
|           return betsByContract[e.id] ?? [] | ||||
|         } else { | ||||
|           return [] | ||||
|         } | ||||
|       }) | ||||
|       const groupContracts = filterDefined( | ||||
|         groupContractIds.map((e) => contractsById[e.contractId]) | ||||
|       ) | ||||
|       const bets = groupContracts.map((e) => betsByContract[e.id] ?? []) | ||||
| 
 | ||||
|       const creatorScores = scoreCreators(groupContracts) | ||||
|       const traderScores = scoreTraders(groupContracts, bets) | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	Block a user