Refactor portfolio query (#1018)

* Fetch less data for portfolio query

* Rename var
This commit is contained in:
James Grugett 2022-10-10 15:51:51 -05:00 committed by GitHub
parent fb0a09664e
commit f03e5d7af0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 58 additions and 40 deletions

View File

@ -1,4 +1,4 @@
import { Dictionary, groupBy, last, sortBy, sum, sumBy, uniq } from 'lodash' import { Dictionary, groupBy, last, sum, sumBy, uniq } from 'lodash'
import { calculatePayout, getContractBetMetrics } from './calculate' import { calculatePayout, getContractBetMetrics } from './calculate'
import { Bet, LimitBet } from './bet' import { Bet, LimitBet } from './bet'
import { import {
@ -199,14 +199,9 @@ export const calculateNewPortfolioMetrics = (
} }
const calculateProfitForPeriod = ( const calculateProfitForPeriod = (
startTime: number, startingPortfolio: PortfolioMetrics | undefined,
descendingPortfolio: PortfolioMetrics[],
currentProfit: number currentProfit: number
) => { ) => {
const startingPortfolio = descendingPortfolio.find(
(p) => p.timestamp < startTime
)
if (startingPortfolio === undefined) { if (startingPortfolio === undefined) {
return currentProfit return currentProfit
} }
@ -221,31 +216,18 @@ export const calculatePortfolioProfit = (portfolio: PortfolioMetrics) => {
} }
export const calculateNewProfit = ( export const calculateNewProfit = (
portfolioHistory: PortfolioMetrics[], portfolioHistory: Record<
'current' | 'day' | 'week' | 'month',
PortfolioMetrics | undefined
>,
newPortfolio: PortfolioMetrics newPortfolio: PortfolioMetrics
) => { ) => {
const allTimeProfit = calculatePortfolioProfit(newPortfolio) const allTimeProfit = calculatePortfolioProfit(newPortfolio)
const descendingPortfolio = sortBy(
portfolioHistory,
(p) => p.timestamp
).reverse()
const newProfit = { const newProfit = {
daily: calculateProfitForPeriod( daily: calculateProfitForPeriod(portfolioHistory.day, allTimeProfit),
Date.now() - 1 * DAY_MS, weekly: calculateProfitForPeriod(portfolioHistory.week, allTimeProfit),
descendingPortfolio, monthly: calculateProfitForPeriod(portfolioHistory.month, allTimeProfit),
allTimeProfit
),
weekly: calculateProfitForPeriod(
Date.now() - 7 * DAY_MS,
descendingPortfolio,
allTimeProfit
),
monthly: calculateProfitForPeriod(
Date.now() - 30 * DAY_MS,
descendingPortfolio,
allTimeProfit
),
allTime: allTimeProfit, allTime: allTimeProfit,
} }

View File

@ -1,6 +1,6 @@
import * as functions from 'firebase-functions' import * as functions from 'firebase-functions'
import * as admin from 'firebase-admin' import * as admin from 'firebase-admin'
import { groupBy, keyBy, last, sortBy } from 'lodash' import { groupBy, keyBy, sortBy } from 'lodash'
import fetch from 'node-fetch' import fetch from 'node-fetch'
import { getValues, log, logMemory, writeAsync } from './utils' import { getValues, log, logMemory, writeAsync } from './utils'
@ -62,11 +62,7 @@ export async function updateMetricsCore() {
const contracts = await getValues<Contract>(firestore.collection('contracts')) const contracts = await getValues<Contract>(firestore.collection('contracts'))
console.log('Loading portfolio history') console.log('Loading portfolio history')
const allPortfolioHistories = await getValues<PortfolioMetrics>( const userPortfolioHistory = await loadPortfolioHistory(users)
firestore
.collectionGroup('portfolioHistory')
.where('timestamp', '>', Date.now() - 31 * DAY_MS) // so it includes just over a month ago
)
console.log('Loading groups') console.log('Loading groups')
const groups = await getValues<Group>(firestore.collection('groups')) const groups = await getValues<Group>(firestore.collection('groups'))
@ -143,11 +139,10 @@ export async function updateMetricsCore() {
) )
const contractsByUser = groupBy(contracts, (contract) => contract.creatorId) const contractsByUser = groupBy(contracts, (contract) => contract.creatorId)
const betsByUser = groupBy(bets, (bet) => bet.userId) const betsByUser = groupBy(bets, (bet) => bet.userId)
const portfolioHistoryByUser = groupBy(allPortfolioHistories, (p) => p.userId)
const userMetrics = users.map((user) => { const userMetrics = users.map((user) => {
const currentBets = betsByUser[user.id] ?? [] const currentBets = betsByUser[user.id] ?? []
const portfolioHistory = portfolioHistoryByUser[user.id] ?? [] const portfolioHistory = userPortfolioHistory[user.id] ?? []
const userContracts = contractsByUser[user.id] ?? [] const userContracts = contractsByUser[user.id] ?? []
const newCreatorVolume = calculateCreatorVolume(userContracts) const newCreatorVolume = calculateCreatorVolume(userContracts)
const newPortfolio = calculateNewPortfolioMetrics( const newPortfolio = calculateNewPortfolioMetrics(
@ -155,12 +150,12 @@ export async function updateMetricsCore() {
contractsById, contractsById,
currentBets currentBets
) )
const lastPortfolio = last(portfolioHistory) const currPortfolio = portfolioHistory.current
const didPortfolioChange = const didPortfolioChange =
lastPortfolio === undefined || currPortfolio === undefined ||
lastPortfolio.balance !== newPortfolio.balance || currPortfolio.balance !== newPortfolio.balance ||
lastPortfolio.totalDeposits !== newPortfolio.totalDeposits || currPortfolio.totalDeposits !== newPortfolio.totalDeposits ||
lastPortfolio.investmentValue !== newPortfolio.investmentValue currPortfolio.investmentValue !== newPortfolio.investmentValue
const newProfit = calculateNewProfit(portfolioHistory, newPortfolio) const newProfit = calculateNewProfit(portfolioHistory, newPortfolio)
@ -303,3 +298,44 @@ const topUserScores = (scores: { [userId: string]: number }) => {
type GroupContractDoc = { contractId: string; createdTime: number } type GroupContractDoc = { contractId: string; createdTime: number }
const BAD_RESOLUTION_THRESHOLD = 0.1 const BAD_RESOLUTION_THRESHOLD = 0.1
const loadPortfolioHistory = async (users: User[]) => {
const now = Date.now()
const userPortfolioHistory = await batchedWaitAll(
users.map((user) => async () => {
const query = firestore
.collection('users')
.doc(user.id)
.collection('portfolioHistory')
.orderBy('timestamp', 'desc')
.limit(1)
const portfolioMetrics = await Promise.all([
getValues<PortfolioMetrics>(query),
getValues<PortfolioMetrics>(
query.where('timestamp', '<', now - DAY_MS)
),
getValues<PortfolioMetrics>(
query.where('timestamp', '<', now - 7 * DAY_MS)
),
getValues<PortfolioMetrics>(
query.where('timestamp', '<', now - 30 * DAY_MS)
),
])
const [current, day, week, month] = portfolioMetrics.map(
(p) => p[0] as PortfolioMetrics | undefined
)
return {
userId: user.id,
current,
day,
week,
month,
}
}),
100
)
return keyBy(userPortfolioHistory, (p) => p.userId)
}