This project is an automation tool for Portfolio Performance. It automatically classifies your securities (Funds, ETFs, Stocks) by retrieving data from Morningstar.
It is a TypeScript adaptation and rewrite of the Python project Alfons1Qto12/pp-portfolio-classifier.
- Multi-Type Support: Handles Funds/ETFs as well as Stocks.
- Automatic Taxonomies: Creates and updates classifications in your XML file:
- Asset Allocation (Equity, Bond, Cash, etc.)
- Regions (Americas, Europe, Asia, etc.)
- Sectors (Technology, Healthcare, Finance, etc.)
- Non-destructive: Generates a new XML file by default to avoid overwriting your data without verification.
- Configurable: Customize the script's behavior (language, taxonomies, etc.) via a configuration file.
- Multi-levels taxonomies: Supports hierarchical taxonomies (e.g., "Europe > Germany").
- Nested taxonomies: Allows to embed a taxonomy into a specific category of another taxonomy.
- Parsing: The script reads your
.xmlfile and extracts all securities with a valid ISIN. - Data Retrieval: It queries Morningstar APIs to fetch:
- Asset Allocation: Breakdown by asset type (Cash, Stocks, Bonds, etc.).
- World Regions: Geographical breakdown (Americas, Europe, Asia, etc.).
- Sectors: Industry breakdown (Technology, Healthcare, Energy, etc.).
- Classification: It maps the retrieved data to the taxonomies defined in your configuration.
- Generation: A new XML file is generated containing your original data plus the new classification categories and assignments.
- Node.js (v22 or higher recommended)
No installation is required, npx will download and install on the fly the latest release of the package.
To run the classification on your portfolio file from the command line prompt, use the following command:
npx pp-portfolio-classifier <path_to_your_portfolio.xml> [output_path.xml]-
Input - The path to your current Portfolio Performance
.xmlfile. -
Output (Optional): The path to save the modified file. Default: input file with suffix
.classified.xml.
The project uses node-config for configuration management.
You can customize the script's behavior (change the taxonomy language, modify the Morningstar domain, etc.) by creating a config/local.json file. This file will override the default values โโdefined in config/default.json. The custom config file (config/local.json) can be located in the same directory as your portfolio file or in the current working directory.
This is ideal for adapting category names to your language or customize taxonomies to your personal preferences.
Example of config/local.json:
{
"mappings": {
"AssetTypeMap": {
"1": "Actions",
"3": "Obligations",
"5": "Obligations",
"6": "Obligations",
"7": "Liquiditรฉs & รฉquivalents",
"8": "Autres",
"99": "Autres"
}
},
"taxonomies": {
"asset_type": {
"active": true,
"name": "Classes dโactifs",
"stockConfig": {
"value": "Actions"
}
},
"region": { "active": false },
"country": { "active": false },
"country_by_region": { "active": true },
"stock_style": { "active": false },
"stock_sector": { "active": true },
"bond_sector": { "active": false },
"holding": { "active": false }
},
"embeddedTaxonomies": {
"stock_style_in_asset": {
"active": true,
"parentCategory": "Actions"
},
"bond_sector_in_asset": {
"active": true,
"parentCategory": "Obligations"
}
}
}Available Taxonomies:
asset_typeenabled by defaultregionenabled if the taxonomy already exists in your portfolio filecountryenabled if the taxonomy already exists in your portfolio filecountry_by_regionenabled by defaultstock_styleenabled if the taxonomy already exists in your portfolio filestock_sectorenabled by defaultbond_sectorenabled if the taxonomy already exists in your portfolio fileholdingdisabled by default as the taxonomy may become huge and difficult to manage for PP.
Configuration fields:
active: Enable/disable this taxonomy. Set totrueto enable,falseto disable, or"auto"to enable it only if the taxonomy already exists in your portfolio file.name: The name of the taxonomy as it will appear in Portfolio Performance.mapping: The key of the mapping table to use for this taxonomy.stockConfig: Specific configuration for stocks.
The classification logic relies on mapping tables defined in the configuration files (config/default.json and config/local.json) to translate Morningstar data into your Portfolio Performance taxonomies.
- Direct Value: For some taxonomies like holding, no mapping table is used. The script directly uses the value provided by Morningstar (e.g., the security name).
- Mapped Value: For most taxonomies, a mapping table is used to convert a code or an ID from Morningstar into a human-readable category name. For instance, AssetTypeMap converts the code 1 to "Stock". If a code is mapped to
null, that specific data point is ignored. This is crucial for avoiding inconsistencies. For example, the region breakdown from Morningstar includes both geographical regions (like "Europe", "Asia") and market types ("Developed Markets", "Emerging Markets"). Without ignoring the market types, the total allocation would exceed 100%. By mapping them tonull, we ensure only the geographical regions are used for the classification.
You can control the classification behavior for specific securities by adding special flags to the Note field in Portfolio Performance.
-
Override ISIN: Use a different ISIN for Morningstar lookup (useful if the security's main ISIN is not found or incorrect in Morningstar).
#PPC:[ISIN2=US0000000000] -
Ignore Classification: Prevent the script from classifying a specific security.
- Ignore all taxonomies:
#PPC:[ignore] - Ignore specific taxonomies (comma separated):
#PPC:[ignore=asset_type,region]
- Ignore all taxonomies:
- Multi-Asset Fund Breakdowns Currently, the tool may produce inconsistent classifications for funds holding multiple asset classes (e.g., 90% Stocks, 10% Bonds). Morningstar reports a breakdown relative to a specific asset class (e.g., "100% of Bonds are Government Bonds"), therfore this percentage will apply to the entire fund instead of weighting it by the asset class portion (i.e., 100% of the 10%). This means a fund with only 10% bonds could be classified as 100% Government Bonds in that specific taxonomy. This is how Morningstar reports data and is a known limitation of the current logic. ๐ Nested taxonomies are a nice workaround to this issue.
- Portfolio Performance file format The script only supports the unencrypted XML (without IDs) file format of Portfolio Performance.
You can now nest taxonomies within specific categories of other taxonomies! This solves the multi-asset fund limitation mentioned above.
Instead of having separate taxonomies, you can embed one taxonomy into a specific category of another taxonomy. The weights are automatically calculated in cascade.
Without embedded taxonomies:
Asset Type: Stock Style:
โโโ Stock: 80% โโโ Large Growth: 70%
โโโ Bond: 20% โโโ Small Value: 30%
With embedded taxonomies:
Asset Type:
โโโ Stock (80%)
โ โโโ Large Growth: 56% โ 80% ร 70%
โ โโโ Small Value: 24% โ 80% ร 30%
โโโ Bond: 20%
Add an embeddedTaxonomies section to your config/local.json:
{
"embeddedTaxonomies": {
"stock_style_in_asset": {
"active": true,
"parentTaxonomy": "asset_type",
"parentCategory": "Stock",
"childTaxonomy": "stock_style",
"targetTaxonomy": "asset_type"
},
"bond_sector_in_asset": {
"active": true,
"parentTaxonomy": "asset_type",
"parentCategory": "Bond",
"childTaxonomy": "bond_sector",
"targetTaxonomy": "asset_type"
}
}
}The above example is already included in the default configuration but is provided here for reference/documentation.
Configuration fields:
active: Enable/disable this embeddingparentTaxonomy: The taxonomy containing the parent categoryparentCategory: The category where to embed the child taxonomychildTaxonomy: The taxonomy to embedtargetTaxonomy: The taxonomy where to create subcategories (usually same as parentTaxonomy)
- Multi-asset funds: Embed stock styles within stocks, bond sectors within bonds
- Detailed breakdowns: Get more granular classifications for specific asset classes
- Better visualization: See the complete hierarchy in a single taxonomy
- Embedded taxonomies are enabled by default as they provide a more accurate classification.
- The total always equals 100% (automatic adjustment if needed)
- If a parent category doesn't exist (0%), the embedding is skipped
- If a child taxonomy has no data, the parent category remains unchanged
- Missing Data: If a security is not classified, it might be because Morningstar does not have data for that specific ISIN, or the ISIN is missing in your Portfolio Performance file.
- Rate Limiting: If you have a very large portfolio, Morningstar might temporarily block requests. The script includes delays to mitigate this.
- Invalid XML: Ensure your input file is a valid Portfolio Performance XML file (unencrypted).
Contributions are welcome! Please submit a pull request to rylorin/pp-portfolio-classifier GitHub repository with your improvements.
This project is licensed under the MIT License. See the LICENSE file for details.
- Based on the original work by Alfons1Qto12/pp-portfolio-classifier.
- Google Gemini
- Kilo Code




