Reports
Report generation and formatting for financial data analysis
Last updated: February 8, 2026
Reports
Report generation for text and table-based financial data views.
Report Types
Text Reports
Simple text-based output with formatted values.
Usage:
```findoc
filename: data.csv
model: portfolioReport
view: report
```
Output:
Report 2025-01
Data Source: Split By Year Month
Output: Get Last Value Per Type For Current Month
---
Portfolio: $150,000.00
Income: $5,000.00
Expenses: $2,500.00
Table Reports
Structured table view with columns.
Usage:
```findoc
filename: data.csv
model: portfolioReport
view: table
```
Output:
| Category | Value | Date |
|---|---|---|
| Portfolio | $150,000.00 | 2025-01 |
| Income | $5,000.00 | 2025-01 |
| Expenses | $2,500.00 | 2025-01 |
Report Data Types
Simple Reports (IReportData)
Single date snapshot with values per category.
Structure:
{
datasets: [
{ label: "Portfolio", data: 150000, date: "2025-01" },
{ label: "Income", data: 5000, date: "2025-01" },
];
}
Models:
portfolioReportportfolioReportTable
Multi-Period Reports (IReportMultiData)
Time series data with multiple periods.
Structure:
{
datasets: {
label: "Income - Expenses",
data: [2500, 3000, 2800],
labels: ["2025-01", "2025-02", "2025-03"]
}
}
Models:
incomeMinusExpensesByYearMonthReportexpensesPlusHouseExpensesByYearMonthReportquarterlyIncomeExpenseReportweeklyExpenseAnalysis
Analysis Reports (IReportMultiData)
Complex multi-metric analysis per entity.
Structure:
{
datasets: [
{
label: "AAPL",
data: [1200, 100, 12],
labels: ["Total Dividends", "Avg Monthly", "Payment Count"],
metadata: {
firstPayment: "2024-01-01",
lastPayment: "2025-01-01",
formatTypes: ["money", "money", "generic"]
}
}
],
summary: {
totalSymbols: 5,
totalDividends: 6000,
totalPayments: 60
}
}
Models:
dividendAnalysisReport
Value Formatting
Reports use model’s chartLabelType for formatting:
Money Format
chartLabelType: "money";
// 1234.56 → $1,234.56
// Locale: en-US, Currency: USD
Percent Format
chartLabelType: "percent";
// 0.15 → 15.00%
Generic Format
chartLabelType: "generic";
// 1234.56 → 1,234.56
Per-Metric Formatting
Analysis reports can specify format per metric via metadata:
metadata: {
formatTypes: ["money", "money", "generic"];
}
// Metric 1: money format
// Metric 2: money format
// Metric 3: generic format
Report Models
Portfolio Snapshot
Model: portfolioReport / portfolioReportTable
Shows latest value per category for current month:
- Portfolio value
- Income total
- Expense total
- Dividend total
- Debt balance
Configuration:
{
dataSource: "splitByYearMonth",
categories: ["Portfolio", "Income", "Cotisation", "Expenses",
"House Expenses", "Dividend", "Debt"],
output: "getLastValuePerTypeForCurrentMonth",
chartLabelType: "money"
}
Custom Date:
```findoc
filename: data.csv
model: portfolioReport
view: table
date: 2024-12-01
```
Income/Expense Analysis
Model: incomeMinusExpensesByYearMonthReport
Monthly net income calculation:
- Income total per month
- Expense total per month
- Net income (Income - Expenses)
Table Output:
| Period | Value |
|---|---|
| 2025-01 | $2,500.00 |
| 2025-02 | $3,000.00 |
| 2025-03 | $2,800.00 |
Dividend Analysis
Model: dividendAnalysisReport
Comprehensive dividend metrics per symbol:
Text View:
AAPL
Total Dividends: $1,200.00
Avg Monthly: $100.00
Payment Count: 12
MSFT
Total Dividends: $800.00
Avg Monthly: $66.67
Payment Count: 12
Table View:
| Symbol | Metric | Value |
|---|---|---|
| AAPL | Total Dividends | $1,200.00 |
| AAPL | Avg Monthly | $100.00 |
| AAPL | Payment Count | 12 |
| MSFT | Total Dividends | $800.00 |
| MSFT | Avg Monthly | $66.67 |
| MSFT | Payment Count | 12 |
Metadata:
- First payment date
- Last payment date
- Total value
- Summary statistics
Report Rendering
ReportRenderer Class
Handles both text and table views:
class ReportRenderer extends MarkdownRenderChild {
private data: IReportData | IReportMultiData;
private modelInfo: IModel;
private viewType: "text" | "table";
async onload() {
if (this.viewType === "table") {
this.renderTableView();
} else {
this.renderTextView();
}
}
}
Text View Rendering
private renderTextView() {
// Title
this.containerEl.createEl("h3", { text: `Report ${date}` });
// Metadata
this.containerEl.createEl("p", { text: dataSource });
this.containerEl.createEl("p", { text: output });
// Separator
this.containerEl.createEl("hr");
// Data entries
datasets.forEach(entry => {
this.containerEl.createEl("span", {
text: `${entry.label}: ${formatValue(entry.data)}`
});
});
}
Table View Rendering
private renderTableView() {
const table = this.containerEl.createEl("table");
table.addClass("findoc-report-table");
// Header row
const headerRow = table.createEl("tr");
headerRow.createEl("th", { text: "Category" });
headerRow.createEl("th", { text: "Value" });
headerRow.createEl("th", { text: "Date" });
// Data rows
datasets.forEach(entry => {
const row = table.createEl("tr");
row.createEl("td", { text: entry.label });
row.createEl("td", { text: formatValue(entry.data) });
row.createEl("td", { text: entry.date });
});
}
Report Generation Functions
getLastValuePerTypeForCurrentMonth
Extracts latest values for current/specified month:
exec: ({ categoriesToSelect, input, date }) => {
const d = date ? new Date(date) : new Date();
const monthKey = `${d.getUTCFullYear()}-${getMonth(d)}`;
const monthData = input[monthKey] || [];
// Keep last value per subcategory (for Portfolio)
// Sum all values for other categories
return {
datasets: categoriesToSelect.map((category) => ({
label: category,
data: sumForCategory(monthData, category),
date: monthKey,
})),
};
};
reportDifference / reportSum
Generate period-by-period calculations:
exec: ({ categoriesToSelect, input, values }) => {
// Calculate per period
const data = labels.map((label) => {
const value1 = sumForCategory(input[label], values[0]);
const value2 = sumForCategory(input[label], values[1]);
return value1 - value2; // or value1 + value2 for reportSum
});
return {
datasets: {
label: `${values[0]} - ${values[1]}`,
data,
labels: Object.keys(input),
},
};
};
reportDividendAnalysis
Complex multi-metric analysis:
exec: ({ categoriesToSelect, input }) => {
// Group by symbol
const symbolData = groupBySymbol(input);
// Calculate metrics per symbol
const results = Object.entries(symbolData).map(([symbol, entries]) => {
const total = sum(entries);
const avgMonthly = total / uniqueMonths(entries).length;
const count = entries.length;
const firstPayment = min(entries.map((e) => e.timestamp));
const lastPayment = max(entries.map((e) => e.timestamp));
return {
label: symbol,
data: [total, avgMonthly, count],
labels: ["Total Dividends", "Avg Monthly", "Payment Count"],
metadata: {
firstPayment,
lastPayment,
formatTypes: ["money", "money", "generic"],
},
};
});
return { datasets: results };
};
Styling
CSS Classes
.findoc-report-table {
/* Table styling */
border-collapse: collapse;
width: 100%;
margin: 1em 0;
}
.findoc-report-table th {
/* Header cells */
background: var(--background-secondary);
padding: 8px;
border: 1px solid var(--border-color);
}
.findoc-report-table td {
/* Data cells */
padding: 8px;
border: 1px solid var(--border-color);
}