Portfolio JSON Format
Portfolio Toolkit uses a structured JSON format (Version 2) for storing portfolio data. This format supports multi-currency transactions, FIFO cost tracking, and comprehensive transaction history.
JSON Structure Overview
The portfolio JSON file has four main sections:
Portfolio Metadata: Basic information about the portfolio
Transactions: Flat array of all transactions (deposits, withdrawals, buys, sells)
Splits: Array of stock split events (optional)
Basic Structure
{
"name": "Portfolio Name",
"currency": "EUR",
"transactions": [
// Array of transaction objects
],
"splits": [
// Array of stock split objects (optional)
]
}
Portfolio Metadata Fields
name
Type: String
Required: Yes
Description: Display name for the portfolio
Example:
"My Investment Portfolio"
currency
Type: String
Required: Yes
Description: Base currency for the portfolio (ISO 4217 code)
Supported: EUR, USD, CAD, GBP, etc.
Example:
"EUR"
Transaction Structure
Each transaction in the transactions
array must include the following fields:
Core Fields
ticker
Type: String or null
Required: Yes
Description: Asset symbol (e.g., “AAPL”) or
null
for cash transactionsExamples:
"AAPL"
,"GOOGL"
,null
date
Type: String
Required: Yes
Format: YYYY-MM-DD
Description: Transaction date
Example:
"2025-06-12"
type
Type: String
Required: Yes
Values:
"buy"
,"sell"
,"deposit"
,"withdrawal"
Description: Type of transaction
quantity
Type: Number
Required: Yes
Description: Number of shares (stocks) or amount (cash)
Example:
10
(shares),1000.00
(cash amount)
price
Type: Number
Required: Yes
Description: Price per share (stocks) or
1.00
(cash)Example:
150.25
(stock price),1.00
(cash)
Currency and Conversion Fields
currency
Type: String
Required: Yes
Description: Currency of the transaction
Example:
"USD"
,"EUR"
,"CAD"
total
Type: Number
Required: Yes
Description: Total amount in transaction currency
Calculation:
quantity × price
Example:
1500.00
exchange_rate
Type: Number
Required: Yes
Description: Exchange rate from transaction currency to base currency
Format: How many units of transaction currency per 1 unit of base currency
Example:
1.056
(EUR/USD rate)
subtotal_base
Type: Number
Required: Yes
Description: Transaction amount in base currency before fees
Calculation:
total ÷ exchange_rate
Example:
1420.45
fees_base
Type: Number
Required: Yes
Description: Transaction fees in base currency
Example:
2.50
total_base
Type: Number
Required: Yes
Description: Total cost in base currency including fees
Calculation:
subtotal_base + fees_base
(buy) orsubtotal_base - fees_base
(sell)Example:
1422.95
Transaction Types
Stock Purchase (Buy)
{
"ticker": "AAPL",
"date": "2025-06-12",
"type": "buy",
"quantity": 10,
"price": 150.00,
"currency": "USD",
"total": 1500.00,
"exchange_rate": 1.056,
"subtotal_base": 1420.45,
"fees_base": 2.50,
"total_base": 1422.95
}
Stock Sale (Sell)
{
"ticker": "AAPL",
"date": "2025-06-15",
"type": "sell",
"quantity": 5,
"price": 155.00,
"currency": "USD",
"total": 775.00,
"exchange_rate": 1.058,
"subtotal_base": 732.58,
"fees_base": 2.00,
"total_base": 730.58
}
Cash Deposit
{
"ticker": null,
"date": "2025-06-10",
"type": "deposit",
"quantity": 1000.00,
"price": 1.00,
"currency": "EUR",
"total": 1000.00,
"exchange_rate": 1.00,
"subtotal_base": 1000.00,
"fees_base": 0.00,
"total_base": 1000.00
}
Cash Withdrawal
{
"ticker": null,
"date": "2025-06-20",
"type": "withdrawal",
"quantity": 500.00,
"price": 1.00,
"currency": "EUR",
"total": 500.00,
"exchange_rate": 1.00,
"subtotal_base": 500.00,
"fees_base": 5.00,
"total_base": 505.00
}
Stock Splits Structure
The splits
array is optional and contains stock split events that automatically adjust historical positions. Each split object includes the following fields:
Split Fields
ticker
Type: String
Required: Yes
Description: Stock symbol that underwent the split
Example:
"EVTL"
,"AAPL"
,"GOOGL"
date
Type: String
Required: Yes
Format: YYYY-MM-DD
Description: Date when the stock split became effective
Example:
"2024-09-23"
ratio
Type: String
Required: Yes
Description: Human-readable split ratio
Format:
"new:old"
(e.g., “2:1” for a 2-for-1 split)Examples:
"2:1"
(split),"4:1"
(split),"1:10"
(reverse split)
split_factor
Type: Number
Required: Yes
Description: Numerical factor to multiply existing shares
Calculation:
new_shares = old_shares × split_factor
Examples:
2.0
(2:1 split),0.1
(1:10 reverse split)
Split Types
Forward Stock Split (2:1)
{
"ticker": "AAPL",
"date": "2024-08-31",
"ratio": "4:1",
"split_factor": 4.0
}
Effect: 100 shares become 400 shares, price adjusts from $200 to $50
Reverse Stock Split (1:10)
{
"ticker": "EVTL",
"date": "2024-09-23",
"ratio": "1:10",
"split_factor": 0.1
}
Effect: 1000 shares become 100 shares, price adjusts from $1 to $10
Split Processing
When a split is processed:
Automatic Adjustment: All positions held before the split date are automatically adjusted
FIFO Preservation: The system maintains FIFO cost basis tracking
Fractional Shares: For reverse splits, fractional shares are converted to cash
Transaction Creation: The system creates sell/buy transactions to represent the split
Note
Splits are processed automatically when loading the portfolio. The original transactions remain unchanged, but the effective position calculations account for all splits.
Complete Split Example
{
"splits": [
{
"ticker": "AAPL",
"date": "2022-08-31",
"ratio": "4:1",
"split_factor": 4.0
},
{
"ticker": "EVTL",
"date": "2024-09-23",
"ratio": "1:10",
"split_factor": 0.1
}
]
}
Complete Example
Here’s a complete portfolio JSON file with splits:
{
"name": "Sample Multi-Currency Portfolio",
"currency": "EUR",
"transactions": [
{
"ticker": null,
"date": "2025-06-01",
"type": "deposit",
"quantity": 5000.00,
"price": 1.00,
"currency": "EUR",
"total": 5000.00,
"exchange_rate": 1.00,
"subtotal_base": 5000.00,
"fees_base": 0.00,
"total_base": 5000.00
},
{
"ticker": "AAPL",
"date": "2025-06-05",
"type": "buy",
"quantity": 20,
"price": 150.00,
"currency": "USD",
"total": 3000.00,
"exchange_rate": 1.056,
"subtotal_base": 2840.91,
"fees_base": 5.00,
"total_base": 2845.91
},
{
"ticker": "SHOP",
"date": "2025-06-08",
"type": "buy",
"quantity": 15,
"price": 80.00,
"currency": "CAD",
"total": 1200.00,
"exchange_rate": 0.639,
"subtotal_base": 766.82,
"fees_base": 8.18,
"total_base": 775.00
},
{
"ticker": "AAPL",
"date": "2025-06-12",
"type": "sell",
"quantity": 5,
"price": 160.00,
"currency": "USD",
"total": 800.00,
"exchange_rate": 1.058,
"subtotal_base": 756.33,
"fees_base": 3.00,
"total_base": 753.33
}
],
"splits": [
{
"ticker": "AAPL",
"date": "2024-08-31",
"ratio": "4:1",
"split_factor": 4.0
},
{
"ticker": "EVTL",
"date": "2024-09-23",
"ratio": "1:10",
"split_factor": 0.1
}
]
}
Validation Rules
The following validation rules apply:
Required Fields
All transaction fields listed above are required
No field can be null except
ticker
for cash transactionsSplit fields are required when
splits
array is present
Data Types
Dates must be in YYYY-MM-DD format
Numbers must be positive (except split_factor which can be any positive number)
Strings must not be empty
Split ratios must follow “new:old” format
Logical Consistency
Cash transactions (
ticker: null
) must haveprice: 1.00
total
must equalquantity × price
Exchange rates must be positive
For base currency transactions,
exchange_rate
should be1.00
Split dates must be valid dates
Split factors must be positive numbers
Split ratios must match the split_factor calculation
Split-Specific Rules
Split dates should be before any dependent transactions
Split factors must be consistent with ratios (e.g., “2:1” → 2.0, “1:10” → 0.1)
Tickers in splits must correspond to actual stock transactions
Multiple splits for the same ticker must be in chronological order
Common Mistakes
Incorrect Exchange Rate Direction
// ❌ Wrong: Using USD/EUR instead of EUR/USD
{
"currency": "USD",
"exchange_rate": 0.946 // This is USD/EUR, not EUR/USD
}
// ✅ Correct: Using EUR/USD
{
"currency": "USD",
"exchange_rate": 1.056 // This is EUR/USD
}
Missing Fee Conversion
// ❌ Wrong: Fees in transaction currency
{
"currency": "USD",
"fees_base": 2.50 // Should be converted to base currency
}
// ✅ Correct: Fees in base currency
{
"currency": "USD",
"exchange_rate": 1.056,
"fees_base": 2.37 // 2.50 USD ÷ 1.056 = 2.37 EUR
}
Inconsistent Totals
// ❌ Wrong: total_base doesn't include fees
{
"subtotal_base": 1000.00,
"fees_base": 5.00,
"total_base": 1000.00 // Should be 1005.00 for buy
}
// ✅ Correct: total_base includes fees
{
"subtotal_base": 1000.00,
"fees_base": 5.00,
"total_base": 1005.00 // For buy transactions
}
Incorrect Split Factor
// ❌ Wrong: Split factor doesn't match ratio
{
"ticker": "AAPL",
"ratio": "2:1",
"split_factor": 0.5 // Should be 2.0 for a 2:1 split
}
// ✅ Correct: Split factor matches ratio
{
"ticker": "AAPL",
"ratio": "2:1",
"split_factor": 2.0 // 2 new shares for 1 old share
}
// ✅ Correct: Reverse split
{
"ticker": "EVTL",
"ratio": "1:10",
"split_factor": 0.1 // 1 new share for 10 old shares
}
Best Practices
Consistent Currency Codes: Use ISO 4217 currency codes (EUR, USD, CAD)
Accurate Exchange Rates: Use exchange rates from the actual transaction date
Include All Fees: Account for all transaction costs in
fees_base
Chronological Order: Sort transactions by date for easier debugging
Validation: Use the validation script to check your portfolio format
Tools and Utilities
Portfolio Toolkit provides several utilities for working with JSON files:
# Validate portfolio format
python tests/validate_examples.py
# Parse and validate portfolio using CLI
portfolio-toolkit portfolio parse examples/portfolio_example.json
# Display portfolio summary with current positions
portfolio-toolkit portfolio summary examples/portfolio_example.json
# Show portfolio performance analysis
portfolio-toolkit portfolio performance examples/portfolio_example.json
# Convert portfolio to different formats
portfolio-toolkit portfolio export examples/portfolio_example.json --format csv
You can also use the CLI to work with portfolio data interactively:
# Show all available portfolio commands
portfolio-toolkit portfolio --help
# Validate portfolio format and check for errors
portfolio-toolkit portfolio validate examples/portfolio_example.json
# Display detailed transaction history
portfolio-toolkit portfolio transactions examples/portfolio_example.json
For more information about CLI commands, see the CLI Reference.