.claude/skills/PortfolioSyncing/SKILL.md
Import and sync broker CSV portfolio data to Google Sheets DataHub. Supports multiple brokers (Fidelity, Schwab, Vanguard, etc.). USE WHEN user mentions import broker data OR sync portfolio OR update positions OR CSV import OR portfolio-sync OR working with Portfolio_Positions CSVs. Handles position updates, SPAXX/margin validation, safety checks, and formula protection.
npx skillsauth add aojdevstudio/finance-guru PortfolioSyncingInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Safely import broker CSV position exports into the Google Sheets DataHub tab, ensuring data integrity, validating changes, and protecting sacred formulas.
Supported Brokers:
Broker Detection: Finance Guru automatically detects your broker from user-profile.yaml (set during onboarding). CSV parsing is tailored to your broker's format.
See: docs/broker-csv-export-guide.md for detailed export instructions per broker.
When executing this workflow, output this notification:
Running the **SyncPortfolio** workflow from the **PortfolioSyncing** skill...
| Workflow | Trigger | File |
|----------|---------|------|
| SyncPortfolio | "sync portfolio", "portfolio-sync", "import fidelity" | workflows/SyncPortfolio.md |
Example 1: Sync after downloading new Fidelity CSV
User: "portfolio-sync"
-> Reads Portfolio_Positions_*.csv and Balances_*.csv from notebooks/updates/
-> Compares with Google Sheets DataHub
-> Updates quantities, cost basis, SPAXX, margin debt
-> Reports changes and validates formulas
Example 2: Update positions after trades
User: "I just bought more JEPI, sync my portfolio"
-> Invokes SyncPortfolio workflow
-> Detects quantity change in JEPI
-> If >10% change, asks for confirmation
-> Updates DataHub with new position data
Example 3: Import new Fidelity export
User: "import fidelity CSV"
-> Locates latest CSV files by date
-> Runs safety checks (position count, large changes)
-> Syncs all positions and cash/margin values
-> Logs update summary
Positions File: notebooks/updates/Portfolio_Positions_MMM-DD-YYYY.csv
Key Fields to Extract:
CSV Format:
Symbol,Quantity,Last Price,Current Value,Total Gain/Loss Dollar,...,Average Cost Basis
TSLA,74,$445.47,$32964.78,+$15634.71,...,$234.19
PLTR,369.746,$188.90,$69845.01,+$60235.59,...,$25.99
Balances File: notebooks/updates/Balances_for_Account_{account_id}.csv
Key Fields to Extract for Cash & Margin:
⚠️ IMPORTANT: Cash Position Logic
SPAXX value from Positions CSV (shows only settled money market)Margin Debt Logic:
IF "Account equity percentage" == 100% THEN
Margin Debt = $0.00
ELSE
Margin Debt = Total Account Value × (1 - Equity Percentage)
END
Read from Google Sheets DataHub:
Identify:
Position Mismatches:
Large Quantity Changes (>10%):
Cost Basis Changes (>20%):
Formula Validation:
Transactions File: notebooks/transactions/History_for_Account_{account_id}.csv
When large quantity changes (>10%) are detected, cross-reference with the transaction history to validate:
Key Fields to Check:
Validation Logic:
For each ticker with >10% change:
1. Read transaction history for that ticker
2. Sum recent BUY transactions since last sync
3. Verify: Current CSV Qty ≈ Previous Sheet Qty + Net Transactions
4. If mismatch > 1 share, FLAG for manual review
Example Cross-Check:
JEPI shows +18.9 shares (90.82 → 109.72)
Transaction History shows:
- Dec 15: BUY JEPI 10 shares
- Dec 18: BUY JEPI 8.9 shares (DRIP)
Total: +18.9 shares ✅ VERIFIED
When to Skip:
Update Column B (Quantity) = CSV Quantity
Update Column G (Avg Cost Basis) = CSV Average Cost Basis
DO NOT TOUCH:
🚨 CRITICAL: NEVER PASS EMPTY STRINGS TO FORMULA COLUMNS
"") will OVERWRITE formulas"") will DELETE formulas in columns C-F - this BREAKS the sheet1. Add new row
2. Set Column A (Ticker) = CSV Symbol
3. Set Column B (Quantity) = CSV Quantity
4. Set Column G (Avg Cost Basis) = CSV Average Cost Basis
5. Apply pattern-based layer classification to Column S:
- If ticker in [JEPI, JEPQ, SPYI, QQQI, CLM, CRF, etc.] → "Layer 2 - Dividend"
- If ticker in [SQQQ] → "Layer 3 - Hedge"
- If ticker in [TSLA, PLTR, NVDA, COIN, MSTR, SOFI] → "Layer 1 - Growth"
- If ticker in [VOO, VTI, FZROX, FNILX] → "Layer 1 - Index"
6. Column C (Last Price) will auto-populate from GOOGLEFINANCE formula
Log Addition:
Added {TICKER} - {SHARES} shares @ ${AVG_COST} - Layer: {LAYER}
Example: Added MSTY - 87.9 shares @ $11.94 - Layer: Layer 2 - Dividend
🚨 CRITICAL: This step is NOT optional. SPAXX and Margin must be updated every sync.
SPAXX (Cash Position) - Row 37, Column L:
1. Read "Settled cash" from Balances CSV
2. If "Settled cash" = 0 → Update DataHub!L37 with " $ - " (zero cash)
3. If "Settled cash" > 0 → Update DataHub!L37 with formatted value
4. ⚠️ SAFETY CHECK: If current sheet SPAXX differs from CSV by >$100, FLAG for user
Pending Activity - Row 38, Column L:
1. Read "Net debit" from Balances CSV (will be negative if margin used)
2. Update DataHub!L38 with this value (format: " $ (X,XXX.XX)" for negative)
Margin Debt - Row 39, Column L:
1. Read "Net debit" from Balances CSV
2. Convert to positive: Margin Debt = ABS(Net debit)
3. Update DataHub!L39 with positive value (format: " $ X,XXX.XX ")
4. If Net debit = 0 → Update with " $ - "
Example:
// Cash position from Balances CSV "Settled cash" = 0
mcp__gdrive__sheets(operation: "updateCells", params: {
spreadsheetId: SPREADSHEET_ID,
range: "DataHub!L37:L37",
values: [[" $ - "]]
})
// Pending Activity from "Net debit" = -7822.71
mcp__gdrive__sheets(operation: "updateCells", params: {
spreadsheetId: SPREADSHEET_ID,
range: "DataHub!L38:L38",
values: [[" $ (7,822.71)"]]
})
// Margin debt = ABS(-7822.71) = 7822.71
mcp__gdrive__sheets(operation: "updateCells", params: {
spreadsheetId: SPREADSHEET_ID,
range: "DataHub!L39:L39",
values: [[" $ 7,822.71 "]]
})
Verify:
Log Update Summary:
✅ Updated 25 positions (quantity + cost basis)
✅ Added 3 new tickers: MSTY, YMAX, AMZY
✅ SPAXX updated: $0 (Settled cash = 0)
✅ Pending Activity: -$7,822.71 (Net debit)
✅ Margin debt: $7,822.71 (ABS of Net debit)
✅ No formula errors detected
✅ Portfolio value: $228,809.41 (matches Fidelity)
Use these patterns to auto-classify new tickers in Column S:
Layer 2 - Dividend (Income funds):
Layer 3 - Hedge (Downside protection):
Layer 1 - Growth (Core holdings):
Layer 1 - Index (Passive core):
STOP conditions (require user confirmation):
FLAG conditions (alert user but proceed):
When STOPPED:
When FLAGGED:
User downloads: Portfolio_Positions_Nov-11-2025.csv
Agent workflow:
Spreadsheet ID: Read from fin-guru/data/user-profile.yaml → google_sheets.portfolio_tracker.spreadsheet_id
THIS WILL BREAK FORMULAS:
// ❌ WRONG - Passing empty strings overwrites formulas in columns C-F
mcp__gdrive__sheets(
operation: "updateCells",
params: {
spreadsheetId: SPREADSHEET_ID,
range: "DataHub!A13:G27", // ❌ Multi-column range
values: [
["JEPI", "72.942", "", "", "", "", "$56.48"], // ❌ Empty strings kill formulas
["JEPQ", "92.043", "", "", "", "", "$58.08"],
["CLM", "763.367", "", "", "", "", "$8.32"]
]
}
)
Why this breaks: Empty strings ("") in columns C-F DELETE the GOOGLEFINANCE and calculation formulas.
THIS PRESERVES FORMULAS:
// ✅ RIGHT - Update ONLY writable columns, one at a time
// Update JEPI quantity (Column B only)
mcp__gdrive__sheets(
operation: "updateCells",
params: {
spreadsheetId: SPREADSHEET_ID,
range: "DataHub!B13:B13", // ✅ Single column, specific row
values: [["72.942"]]
}
)
// Update JEPI cost basis (Column G only)
mcp__gdrive__sheets(
operation: "updateCells",
params: {
spreadsheetId: SPREADSHEET_ID,
range: "DataHub!G13:G13", // ✅ Single column, specific row
values: [["$56.48"]]
}
)
// Add new ticker (Columns A, B, G - formulas in C-F will auto-populate)
mcp__gdrive__sheets(
operation: "updateCells",
params: {
spreadsheetId: SPREADSHEET_ID,
range: "DataHub!A28:A28", // ✅ Ticker only
values: [["ECAT"]]
}
)
mcp__gdrive__sheets(
operation: "updateCells",
params: {
spreadsheetId: SPREADSHEET_ID,
range: "DataHub!B28:B28", // ✅ Quantity only
values: [["72.884"]]
}
)
mcp__gdrive__sheets(
operation: "updateCells",
params: {
spreadsheetId: SPREADSHEET_ID,
range: "DataHub!G28:G28", // ✅ Cost basis only
values: [["$15.92"]]
}
)
Why this works: Only touching columns A, B, G leaves formulas in C-F intact and functional.
| Action | ✅ GOOD | ❌ BAD |
|--------|---------|--------|
| Update quantity | range: "DataHub!B13:B13" | range: "DataHub!A13:G13" with ["", "72.942", "", "", "", "", ""] |
| Update cost basis | range: "DataHub!G13:G13" | Including columns C-F in range |
| Add new ticker | 3 separate calls (A, B, G) | Single call with empty strings in C-F |
| Multiple tickers | Loop through rows, update B and G individually | Batch update entire range A:G |
Golden Rule: NEVER include columns C-F in your update range. NEVER pass empty strings to any cell.
Builder (Write-enabled):
All Other Agents (Read-only):
For complete architecture details, see:
fin-guru/data/spreadsheet-architecture.mdfin-guru/data/spreadsheet-quick-ref.mdfin-guru/data/user-profile.yamlBefore importing CSV:
Portfolio_Positions_*.csv) is latest by dateBalances_for_Account_*.csv) is available and currentnotebooks/updates/ directory⚠️ BOTH CSVs Required: Positions CSV alone is insufficient. Balances CSV provides:
Skill Type: Domain (workflow guidance) Enforcement: BLOCK (data integrity critical) Priority: Critical Line Count: < 300 (following 500-line rule) ✅
development
Sync retirement account data from Vanguard and Fidelity CSV exports to Google Sheets DataHub. Handles multiple accounts, aggregates holdings by ticker, and updates quantities in retirement section (rows 46-62). Triggers on sync retirement, update retirement, vanguard sync, 401k update, IRA sync, or working with notebooks/retirement-accounts/ files.
devops
Update Margin Dashboard with Fidelity balance data and calculate margin-living strategy metrics. Monitors margin balance, interest costs, coverage ratios, and scaling thresholds. Triggers safety alerts for large draws and provides time-based scaling recommendations. Use when updating margin, balances, coverage ratio, or margin strategy analysis.
development
Prevent accidental modification of sacred spreadsheet formulas in Google Sheets Portfolio Tracker. Blocks edits to GOOGLEFINANCE formulas, calculated columns, and total rows. Allows only IFERROR wrappers, fixing broken references, and expanding ranges. Triggers on update formula, modify column, fix errors, or any attempt to edit formula-based cells.
development
Develop comprehensive portfolio strategies from quantitative analysis. Integrates margin, dividend, and cash-flow tactics into actionable wealth-building plans.