- Quick Start
- Development Setup
- Project Architecture
- Building the Project
- Contributing Code
- Development Guides
- Getting Help
- Appendix
Thanks for your interest in contributing! We welcome improvements of all sizes — from small bug fixes to larger features. To make collaboration smooth and reviews efficient, please keep the following guidelines in mind:
- Keep pull requests small and focused on a single feature or fix. The shorter and clearer the change, the easier it is to review.
- Use the standard code formatting, but avoid reformatting code that’s unrelated to your change.
- For larger changes, open a draft pull request early to outline your idea and gather feedback before investing too much time polishing.
- Follow existing code patterns and conventions throughout the project.
- Write concise comments where they help future readers understand important decisions.
- Add tests for calculation logic, especially in the
name.abuchen.portfoliobundle. Avoid modifying existing tests unless a breaking or incompatible change makes it necessary.
Eclipse IDE is required for Portfolio Performance development as the application is built on Eclipse RCP (Rich Client Platform).
Prerequisites
- Java 21 - Required minimum version (Download from Azul)
- Eclipse IDE for RCP and RAP Developers - Download the RCP package
Plugins from the Eclipse Marketplace
Install via Eclipse Marketplace (drag and drop the Install button to your workspace):
- Infinitest - Continuous testing
- ResourceBundle Editor - Translation file editing
- Checkstyle Plug-In - Code style checking
- SonarQube for IDE - Code quality analysis
- Launch Configuration DSL - Launch configuration management
Plugins from the Eclipse Update Site
Menu → Help → Install New Software → Select Latest Eclipse Simultaneous Release:
- M2E PDE Integration (under General Purpose Tools)
- Eclipse e4 Tools (under General Purpose Tools)
Configure Eclipse
Menu → Window → Preferences:
Java→Editor→Save Actions- ✓ Format Source Code → Format edited lines
- ✓ Organize imports
Java→Editor→Content Assist- ✓ Add import instead of qualified name
- ✓ Use static imports
Java→Editor→Content Assist→Favorites- Add these types for import suggestions:
name.abuchen.portfolio.util.TextUtilname.abuchen.portfolio.datatransfer.ExtractorUtilsname.abuchen.portfolio.datatransfer.ExtractorMatchersname.abuchen.portfolio.datatransfer.ExtractorTestUtilitiesname.abuchen.portfolio.junit.TestUtilities
- Add these types for import suggestions:
Java→Installed JREs- Add Java 21 JDK
Project Setup
- Fork your repository using GitHub's fork workflow
- Import projects: Within Eclipse, clone and import all projects
- Setup target platform:
- Open
portfolio-target-definitionproject - Open
portfolio-target-definition.targetfile (right-click → Open With → Target Editor) - Click "Set as Active Target Platform" (requires Internet, may take time)
- Open
- Add Launch Configuration view:
Menu→Window→Show View→Other...→Debug→Launch Configuration - Run the application: Select
Eclipse Application→PortfolioPerformanceand right-click Run - Run tests: Select
JUnit Plug-in Tests→PortfolioPerformance_TestsorPortfolioPerformance_UI_Tests
Optional Language Packs
Install via Menu → Help → Install New Software:
- Update site:
https://download.eclipse.org/technology/babel/update-site/latest/ - Select desired language packs
- Force language with
-nlparameter:eclipse.exe -nl de
Portfolio Performance is built on Eclipse RCP (Rich Client Platform) with an E4 application model, providing a modular plugin-based architecture.
Key Technologies
- Eclipse RCP - Rich Client Platform framework
- OSGi Bundles - Modular plugin architecture with clear separation of concerns
- Maven + Tycho - Eclipse-specific build system
- Java 21 - Minimum required version
- Dependency Injection - Jakarta annotations (@Inject, @PostConstruct, @PreDestroy)
- Event-driven communication - E4 event broker + PropertyChangeSupport
Module Structure
portfolio-target-definition # Eclipse dependencies
↓
name.abuchen.portfolio # Core domain & business logic
↓
name.abuchen.portfolio.ui # User interface layer
↓
portfolio-product # Application packaging
Test Infrastructure:
name.abuchen.portfolio.tests # Core module tests
name.abuchen.portfolio.ui.tests # UI module tests
Finding Your Way
- Domain Layer:
name.abuchen.portfolio/src/name/abuchen/portfolio/model/- Core entities (Client, Portfolio, Account, Security) - PDF Importers:
name.abuchen.portfolio/src/name/abuchen/portfolio/datatransfer/pdf/- Bank statement parsers - UI Components:
name.abuchen.portfolio.ui/src/name/abuchen/portfolio/ui/- User interface
Run the application:
- Launch Configuration view →
Eclipse Application→PortfolioPerformance→ Right-click Run
Run tests:
- Core tests:
JUnit Plug-in Tests→PortfolioPerformance_Tests - UI tests:
JUnit Plug-in Tests→PortfolioPerformance_UI_Tests
Maven is used for CI/CD builds. Local development can use Eclipse or Maven.
Prerequisites:
JAVA_HOMEpoints to Java 21 JDK- Maven installed
Standard Build:
# Linux/macOS
export MAVEN_OPTS="-Xmx4g"
mvn -f portfolio-app/pom.xml clean verify
# Windows
set MAVEN_OPTS="-Xmx4g"
mvn -f portfolio-app/pom.xml clean verifyBuild Core Module Only:
mvn -f portfolio-app/pom.xml clean compile \
-pl :portfolio-target-definition,:name.abuchen.portfolio.pdfbox1,:name.abuchen.portfolio.pdfbox3,:name.abuchen.portfolio -am -amdRun Core Tests:
mvn -f portfolio-app/pom.xml verify -o \
-pl :portfolio-target-definition,:name.abuchen.portfolio.pdfbox1,:name.abuchen.portfolio.pdfbox3,:name.abuchen.portfolio,:name.abuchen.portfolio.junit,:name.abuchen.portfolio.tests -am -amdRun Single Test Class:
mvn -f portfolio-app/pom.xml verify -o \
-pl :portfolio-target-definition,:name.abuchen.portfolio.pdfbox1,:name.abuchen.portfolio.pdfbox3,:name.abuchen.portfolio,:name.abuchen.portfolio.junit,:name.abuchen.portfolio.tests -am -amd \
-Dtest=<fully qualified test class name>You can use the profile -Plocal-dev for a faster locale build. However, keep in mind that this skips the translation bundles, checkstyle checks, and other checks.
- Use
varkeyword where possible for local variables - Format source code using Eclipse formatter (configured in project)
- Exception: Do NOT reformat PDF importer files - carefully insert code manually
- Use
@formatter:offand@formatter:onto protect formatting
- Organize imports automatically (save action enabled)
- Add static imports for utility classes (ExtractorUtils, TextUtil, etc.)
- Add test cases for new functionality in
name.abuchen.portfolio.tests - No UI tests required
- Test all calculations and business logic thoroughly
- Use custom matchers when testing PDF importers
Commit Messages
Write commit messages in English:
Short summary (50 chars or less)
More detailed explanation if needed. Wrap at 72 characters.
Explain what and why, not how.
Closes #123
Issue: https://forum.portfolio-performance.info/t/...
- Link GitHub issues:
Closes #<ISSUE NUMBER>after empty line - Link forum threads:
Issue: https://...with forum post URL
Pull Request Process:
- Rebase your branch on latest
master(do NOT merge master into your branch) - Format your code (except PDF importers - manual formatting only)
- Create Pull Request via GitHub or GitHub Desktop
PDF importers extract transactions from bank and broker PDF statements. Each bank/broker has its own extractor class.
How it works:
- User selects PDF files via import menu or drag-and-drop
- PDFBox converts PDF to text (one string per line)
- Each extractor applies regex patterns to extract transactions
- Results are presented to user for review and import
Creating Debug Files:
File → Import → Debug: Create text from PDF...
- Remove all personal data
- Do NOT insert new lines, breaks, or spaces
- Keep original PDF text structure intact
Source Locations:
- Extractors:
name.abuchen.portfolio/src/name/abuchen/portfolio/datatransfer/pdf/ - Tests:
name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/pdf/ - Naming:
BankNamePDFExtractor.javaandBankNamePDFExtractorTest.java
Current Reference Implementations:
- Baader Bank AG - Modern comprehensive implementation
- Comdirect Bank AG - Advanced post-processing
- Saxo Bank A/S - Complex pattern matching
Test File Naming Convention:
Use local language with two-digit counter:
Buy01.txt,Sell01.txt- Purchase and saleDividend01.txt- DividendsWertpapiereingang01.txt- Incoming securities (German example)GiroKontoauszug01.txt- Bank account statement (German example)
Modern Test Pattern (Preferred):
Use ExtractorMatchers for readable assertions:
@Test
public void testWertpapierKauf01()
{
var extractor = new ScalableCapitalPDFExtractor(new Client());
List<Exception> errors = new ArrayList<>();
var results = extractor.extract(PDFInputFile.loadTestCase(getClass(), "Kauf01.txt"), errors);
assertThat(errors, empty());
assertThat(countSecurities(results), is(1L));
assertThat(countBuySell(results), is(1L));
assertThat(countAccountTransactions(results), is(0L));
assertThat(countAccountTransfers(results), is(0L));
assertThat(countItemsWithFailureMessage(results), is(0L));
assertThat(results.size(), is(2));
new AssertImportActions().check(results, "EUR");
// check security
assertThat(results, hasItem(security( //
hasIsin("IE0008T6IUX0"), hasWkn(null), hasTicker(null), //
hasName("Vngrd Fds-ESG Dv.As-Pc Al ETF"), //
hasCurrencyCode("EUR"))));
// check dividends transaction
assertThat(results, hasItem(purchase( //
hasDate("2024-12-12T13:12:51"), hasShares(3.00), //
hasSource("Kauf01.txt"), //
hasNote("Ord.-Nr.: SCALsin78vS5CYz"), //
hasAmount("EUR", 19.49), hasGrossValue("EUR", 18.50), //
hasTaxes("EUR", 0.00), hasFees("EUR", 0.99))));
}See BaaderBankPDFExtractorTest for examples.
Key Utilities:
- AbstractPDFExtractor - Base class
- ExtractorUtils - Amount conversion, tax/fee processing
- ExtractorMatchers - Modern test assertions
- TextUtil - String manipulation for PDF text
Important Notes:
- Do NOT auto-format PDF extractor files (use
@formatter:off/@formatter:on) - Test files must be UTF-8 encoded
- Anonymize personal data but preserve structure
- Match all special characters with
.(dot) in regex
The Interactive Broker Flex Query importer handles XML-compliant Interactive Broker Activity Statements.
Source Locations:
- Importer:
name.abuchen.portfolio/src/name/abuchen/portfolio/datatransfer/ibflex/ - Tests:
name.abuchen.portfolio.tests/src/name/abuchen/portfolio/datatransfer/ibflex/
Reference:
Portfolio Performance is translated into multiple languages using POEditor.
Contributing Translations:
- Register with POEditor project
- Open a ticket for new languages
- Translations are merged before each release
For Code Contributors:
- Use Source → Externalize Strings in Eclipse
- Use ResourceBundle Editor for editing
- Translate new labels to all languages using DeepL
Label Naming Conventions:
Label- Short labelsMsg- Longer messagesColumn- Column headersPDF,CSV,Preferences- Specific area prefixes (use sparingly)
Trade calendars track trading-free days (weekends, holidays, exchange-specific closures).
Source Locations:
- Manager:
name.abuchen.portfolio/src/name/abuchen/portfolio/util/TradeCalendarManager.java - Calendar Class:
name.abuchen.portfolio/src/name/abuchen/portfolio/util/TradeCalendar.java - Tests:
name.abuchen.portfolio.tests/src/name/abuchen/portfolio/util/TradeCalendarTest.java
Structure:
code- Unique identifier (e.g.,nyse)description- Display label (e.g., "New York Stock Exchange")weekend- Default weekend days
All images and icons must be Creative Commons CC0 licensed.
Sources
- Use icons from iconmonstr.com only
- Register all images in Images.java
- Use SVG format with width and height set to 16px; add a fill color if needed
- Note: For historical reasons, some icons are still available in PNG format with two resolutions (@1x and @2x). New icons should use SVG format only.
Color Guidelines
- Passive state: #393E42 (dark, cool gray)
- Active state: #F18F01 (orange)
- Error state: #D11D1D (dark red)
See Color Code Reference for exact colors.
Test regular expressions at regex101.com.
Best Practices:
- Match special characters (
äöüÄÖÜß, circumflex, etc.) with.(dot) - PDF conversion varies - Escape special regex characters:
$^{[(|)]}*+?\ .match(" ... ")- Use anchors^...$.find(" ... ")- Do NOT add anchors (added automatically)
Patterns that Work Well
| Value | Example | Works Well |
|---|---|---|
| Date | 01.01.1970 | [\\d]{2}\\.[\\d]{2}\\.[\\d]{4} |
| Date | 1.1.1970 | [\\d]{1,2}\\.[\\d]{1,2}\\.[\\d]{4} |
| Time | 12:01 | [\\d]{2}\\:[\\d]{2} |
| ISIN | IE00BKM4GZ66 | [A-Z]{2}[A-Z0-9]{9}[0-9] |
| WKN | A111X9 | [A-Z0-9]{6} |
| Valoren | 1098758 | [A-Z0-9]{5,9} |
| SEDOL | B5B74S0 | [A-Z0-9]{7} |
| CUSIP | 11135F101 | [A-Z0-9]{9} |
| TickerSymbol | AAPL, BRK.B | [A-Z0-9]{1,6}(?:\\.[A-Z]{1,4})? |
| Crypto Ticker | BTC, ETH-BTC | [A-Z0-9]{1,5}(?:[\\-\\/][A-Z0-9]{1,5})? |
| Amount | 751,68 | [\\.,\\d]+ or [\\.\\d]+,[\\d]{2} |
| Amount | 74'120.00 | [\\.'\\d]+ |
| Amount | 20 120.00 | [\\.\\d\\s]+ |
| Currency | EUR | [A-Z]{3} |
| Currency Symbol | € or $ | \\p{Sc} |





