import { BigNumberJS } from '../../BigNumberJS' import { DateTime } from 'luxon' export interface IFinancialsConstructor { expectedAppreciationPercentage: string expectedGrossMonthlyRent: string maintenanceCost: string incomeTaxesPercentage: string marketCap: string price: string priceHistory: ITokenDayDataJSON[] | null } export interface ITokenDayDataJSON { date: string price: string } export interface ITokenDayData { date: DateTime price: BigNumberJS } export class Financials { public readonly expectedAppreciationPercentage: BigNumberJS public readonly expectedGrossMonthlyRent: BigNumberJS public readonly maintenanceCost: BigNumberJS public readonly incomeTaxesPercentage: BigNumberJS public readonly marketCap: BigNumberJS public readonly price: BigNumberJS public readonly priceHistory: ITokenDayData[] | null public readonly volatility: BigNumberJS public constructor({ expectedAppreciationPercentage, expectedGrossMonthlyRent, maintenanceCost, incomeTaxesPercentage, marketCap, price, priceHistory, }: IFinancialsConstructor) { this.expectedAppreciationPercentage = new BigNumberJS(expectedAppreciationPercentage) this.expectedGrossMonthlyRent = new BigNumberJS(expectedGrossMonthlyRent) this.maintenanceCost = new BigNumberJS(maintenanceCost) this.incomeTaxesPercentage = new BigNumberJS(incomeTaxesPercentage) this.marketCap = new BigNumberJS(marketCap) this.price = new BigNumberJS(price) this.priceHistory = this.mapPriceHistory(priceHistory) this.volatility = this.calculateVolatility(this.priceHistory) } public get monthlyTaxes() { return this.expectedGrossMonthlyRent .times(this.incomeTaxesPercentage) .div(100) } public get netRentMonthly() { return this.expectedGrossMonthlyRent .minus(this.maintenanceCost) .minus(this.monthlyTaxes) } public get netRentYearly() { return this.netRentMonthly.times(12) } public get expectedRentIncome() { return this.netRentYearly.div(this.marketCap).times(100) } private mapPriceHistory(rawPriceHistory: ITokenDayDataJSON[] | null): ITokenDayData[] | null { if (!rawPriceHistory) return null const length = rawPriceHistory?.length || 0 const priceHistory = rawPriceHistory .map(({ date, price }) => ({ date: DateTime.fromISO(date), price: new BigNumberJS(price), })) .sort((a, b) => a.date.toMillis() - b.date.toMillis()) const initialTimestamp = priceHistory[0]?.date || DateTime.now() return [ ...Array(30 - length).fill(null).map((_, index) => ({ date: initialTimestamp.minus({ days: 30 - length - index }), price: new BigNumberJS(1), })), ...priceHistory, ] } private calculateVolatility(priceHistory: ITokenDayData[] | null) { if (!priceHistory) return new BigNumberJS(0) return new BigNumberJS(priceHistory[priceHistory.length - 1].price) .div(priceHistory[0].price) .minus(1) .times(100) } }