Skip to content

Commit

Permalink
Add token price report
Browse files Browse the repository at this point in the history
  • Loading branch information
sophialittlejohn committed Dec 5, 2024
1 parent 5bc3b42 commit 0c767ce
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 17 deletions.
38 changes: 31 additions & 7 deletions src/Reports/Processor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ import {
FeeTransactionsData,
FeeTransactionReportFilter,
FeeTransactionReport,
TokenPriceReport,
TokenPriceReportFilter,
TokenPriceData,
} from './types.js'

export class Processor {
Expand All @@ -28,7 +31,7 @@ export class Processor {
* @param filter Optional filtering and grouping options
* @returns Processed balance sheet report at the end of each period
*/
balanceSheet(data: BalanceSheetData, filter?: ReportFilter): BalanceSheetReport[] {
balanceSheet(data: BalanceSheetData, filter?: Omit<ReportFilter, 'to' | 'from'>): BalanceSheetReport[] {
const items: BalanceSheetReport[] = data?.poolSnapshots?.map((snapshot) => {
const tranches = data.trancheSnapshots[this.getDateKey(snapshot.timestamp)] ?? []
if (tranches.length === 0) throw new Error('No tranches found for snapshot')
Expand Down Expand Up @@ -63,7 +66,7 @@ export class Processor {
* @param filter Optional filtering and grouping options
* @returns Processed cashflow report at the end of each period
*/
cashflow(data: CashflowData, filter?: ReportFilter): CashflowReport[] {
cashflow(data: CashflowData, filter?: Omit<ReportFilter, 'to' | 'from'>): CashflowReport[] {
const subtype = data.metadata?.pool.asset.class === 'Public credit' ? 'publicCredit' : 'privateCredit'
const items: CashflowReport[] = data.poolSnapshots.map((day) => {
const poolFees =
Expand Down Expand Up @@ -110,7 +113,7 @@ export class Processor {
* @param filter Optional filtering and grouping options
* @returns Processed profit and loss report at the end of each period
*/
profitAndLoss(data: ProfitAndLossData, filter?: ReportFilter): ProfitAndLossReport[] {
profitAndLoss(data: ProfitAndLossData, filter?: Omit<ReportFilter, 'to' | 'from'>): ProfitAndLossReport[] {
const items: ProfitAndLossReport[] = data.poolSnapshots.map((day) => {
const subtype = data.metadata?.pool.asset.class === 'Public credit' ? 'publicCredit' : 'privateCredit'
const profitAndLossFromAsset =
Expand Down Expand Up @@ -152,7 +155,7 @@ export class Processor {

investorTransactions(
data: InvestorTransactionsData,
filter?: InvestorTransactionsReportFilter
filter?: Omit<InvestorTransactionsReportFilter, 'to' | 'from'>
): InvestorTransactionsReport[] {
if (!data.investorTransactions?.length) return []

Expand Down Expand Up @@ -208,7 +211,10 @@ export class Processor {
}, [])
}

assetTransactions(data: AssetTransactionsData, filter?: AssetTransactionReportFilter): AssetTransactionReport[] {
assetTransactions(
data: AssetTransactionsData,
filter?: Omit<AssetTransactionReportFilter, 'to' | 'from'>
): AssetTransactionReport[] {
const typeMap: Record<
NonNullable<Exclude<AssetTransactionReportFilter['transactionType'], 'all'>>,
AssetTransaction['type']
Expand Down Expand Up @@ -243,7 +249,10 @@ export class Processor {
}, [])
}

feeTransactions(data: FeeTransactionsData, filter?: FeeTransactionReportFilter): FeeTransactionReport[] {
feeTransactions(
data: FeeTransactionsData,
filter?: Omit<FeeTransactionReportFilter, 'to' | 'from'>
): FeeTransactionReport[] {
return data.poolFeeTransactions.reduce<FeeTransactionReport[]>((acc, tx) => {
if (!filter?.transactionType || filter.transactionType === 'all' || filter.transactionType === tx.type) {
acc.push({
Expand All @@ -257,6 +266,21 @@ export class Processor {
}, [])
}

tokenPrice(data: TokenPriceData, filter?: Omit<TokenPriceReportFilter, 'to' | 'from'>): TokenPriceReport[] {
const items = Object.entries(data.trancheSnapshots).map(([timestamp, snapshots]) => ({
type: 'tokenPrice' as const,
timestamp: timestamp,
tranches: snapshots.map((snapshot) => ({
timestamp: snapshot.timestamp,
name: snapshot.pool.currency.symbol,
price: snapshot.price ?? new Price(0n),
supply: snapshot.tokenSupply,
})),
}))

return groupByPeriod<TokenPriceReport>(items, filter?.groupBy ?? 'day', 'latest')
}

Check warning on line 282 in src/Reports/Processor.ts

View check run for this annotation

Codecov / codecov/patch

src/Reports/Processor.ts#L270-L282

Added lines #L270 - L282 were not covered by tests

/**
* Apply grouping to a report.
* @param items Report items
Expand All @@ -270,7 +294,7 @@ export class Processor {
private applyGrouping<
T extends {
timestamp: string
[key: string]: Currency | string | { [key: string]: any } | number | undefined
[key: string]: Currency | Price | Token | string | number | undefined | any[] | { [key: string]: any }
},
>(items: T[], groupBy: ReportFilter['groupBy'] = 'day', strategy: 'latest' | 'sum' = 'latest'): T[] {
if (strategy === 'latest') {
Expand Down
30 changes: 22 additions & 8 deletions src/Reports/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ import {
InvestorTransactionsReportFilter,
AssetTransactionReport,
AssetTransactionReportFilter,
TokenPriceReport,
TokenPriceReportFilter,
} from './types.js'
import { Query } from '../types/query.js'
import {
Expand Down Expand Up @@ -71,6 +73,10 @@ export class Reports extends Entity {
return this._generateReport<AssetTransactionReport>('assetTransactions', filter)
}

tokenPrice(filter?: TokenPriceReportFilter) {
return this._generateReport<TokenPriceReport>('tokenPrice', filter)
}

Check warning on line 78 in src/Reports/index.ts

View check run for this annotation

Codecov / codecov/patch

src/Reports/index.ts#L77-L78

Added lines #L77 - L78 were not covered by tests

/**
* Reports are split into two types:
* - A `Report` is a standard report: balanceSheet, cashflow, profitAndLoss
Expand All @@ -92,12 +98,14 @@ export class Reports extends Entity {
filter?.assetId,
],
() => {
const { from, to, ...restFilter } = filter ?? {}
const dateFilter = {
timestamp: {
greaterThan: filter?.from,
lessThanOrEqualTo: filter?.to && `${filter.to.split('T')[0]}T23:59:59.999Z`,
greaterThan: from,
lessThanOrEqualTo: to && `${to.split('T')[0]}T23:59:59.999Z`,
},
}
console.log('🚀 ~ dateFilter:', dateFilter)

const metadata$ = this.pool.metadata()

Expand Down Expand Up @@ -131,34 +139,40 @@ export class Reports extends Entity {
return combineLatest([poolSnapshots$, trancheSnapshots$]).pipe(
map(
([poolSnapshots, trancheSnapshots]) =>
processor.balanceSheet({ poolSnapshots, trancheSnapshots }, filter) as T[]
processor.balanceSheet({ poolSnapshots, trancheSnapshots }, restFilter) as T[]
)
)
case 'cashflow':
return combineLatest([poolSnapshots$, poolFeeSnapshots$, metadata$]).pipe(
map(
([poolSnapshots, poolFeeSnapshots, metadata]) =>
processor.cashflow({ poolSnapshots, poolFeeSnapshots, metadata }, filter) as T[]
processor.cashflow({ poolSnapshots, poolFeeSnapshots, metadata }, restFilter) as T[]
)
)
case 'profitAndLoss':
return combineLatest([poolSnapshots$, poolFeeSnapshots$, metadata$]).pipe(
map(
([poolSnapshots, poolFeeSnapshots, metadata]) =>
processor.profitAndLoss({ poolSnapshots, poolFeeSnapshots, metadata }, filter) as T[]
processor.profitAndLoss({ poolSnapshots, poolFeeSnapshots, metadata }, restFilter) as T[]
)
)
case 'investorTransactions':
return combineLatest([investorTransactions$, metadata$]).pipe(
map(([investorTransactions]) => processor.investorTransactions({ investorTransactions }, filter) as T[])
map(
([investorTransactions]) => processor.investorTransactions({ investorTransactions }, restFilter) as T[]
)
)
case 'assetTransactions':
return combineLatest([assetTransactions$, metadata$]).pipe(
map(([assetTransactions]) => processor.assetTransactions({ assetTransactions }, filter) as T[])
map(([assetTransactions]) => processor.assetTransactions({ assetTransactions }, restFilter) as T[])
)
case 'feeTransactions':
return combineLatest([poolFeeTransactions$]).pipe(
map(([poolFeeTransactions]) => processor.feeTransactions({ poolFeeTransactions }, filter) as T[])
map(([poolFeeTransactions]) => processor.feeTransactions({ poolFeeTransactions }, restFilter) as T[])
)

Check warning on line 172 in src/Reports/index.ts

View check run for this annotation

Codecov / codecov/patch

src/Reports/index.ts#L170-L172

Added lines #L170 - L172 were not covered by tests
case 'tokenPrice':
return combineLatest([trancheSnapshots$]).pipe(
map(([trancheSnapshots]) => processor.tokenPrice({ trancheSnapshots }, restFilter) as T[])
)

Check warning on line 176 in src/Reports/index.ts

View check run for this annotation

Codecov / codecov/patch

src/Reports/index.ts#L174-L176

Added lines #L174 - L176 were not covered by tests
default:
throw new Error(`Unsupported report type: ${type}`)
Expand Down
24 changes: 22 additions & 2 deletions src/Reports/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { PoolFeeTransaction } from '../queries/poolFeeTransactions.js'
import { PoolSnapshot } from '../queries/poolSnapshots.js'
import { TrancheSnapshotsByDate } from '../queries/trancheSnapshots.js'
import { PoolMetadata } from '../types/poolMetadata.js'
import { Price } from '../utils/BigInt.js'
import { Price, Token } from '../utils/BigInt.js'

Check warning on line 8 in src/Reports/types.ts

View check run for this annotation

Codecov / codecov/patch

src/Reports/types.ts#L8

Added line #L8 was not covered by tests
import { Currency } from '../utils/BigInt.js'
import { GroupBy } from '../utils/date.js'

Expand All @@ -21,7 +21,7 @@ export type DataReportFilter = {
}

export type Report = 'balanceSheet' | 'cashflow' | 'profitAndLoss'
export type DataReport = 'investorTransactions' | 'assetTransactions'
export type DataReport = 'investorTransactions' | 'assetTransactions' | 'feeTransactions' | 'tokenPrice'

/**
* Balance sheet type
Expand Down Expand Up @@ -135,6 +135,7 @@ export type InvestorTransactionsReport = {
epoch: string
transactionType: SubqueryInvestorTransactionType
currencyAmount: Currency
// TODO: probably needs to be an array of tranches
trancheTokenId: string
trancheTokenAmount: Currency
price: Price
Expand Down Expand Up @@ -193,3 +194,22 @@ export type FeeTransactionReportFilter = {
to?: string
transactionType?: 'directChargeMade' | 'directChargeCanceled' | 'accrued' | 'paid' | 'all'
}

/**
* Token price types
*/
export type TokenPriceData = {
trancheSnapshots: TrancheSnapshotsByDate
}

export type TokenPriceReport = {
type: 'tokenPrice'
timestamp: string
tranches: { name: string; price: Price; supply: Token; timestamp: string }[]
}

export type TokenPriceReportFilter = {
from?: string
to?: string
groupBy?: GroupBy
}

Check warning on line 215 in src/Reports/types.ts

View check run for this annotation

Codecov / codecov/patch

src/Reports/types.ts#L122-L215

Added lines #L122 - L215 were not covered by tests

0 comments on commit 0c767ce

Please sign in to comment.