Update Margin Dashboard with Fidelity balance data and calculate margin-living strategy metrics. Monitors margin balance, interest costs, coverage ratios, and scaling thresholds...
Monitor and manage margin-living strategy by tracking margin balances, interest costs, dividend coverage ratios, and portfolio-to-margin safety thresholds. Provides data-driven scaling recommendations based on strategy milestones.
This skill reads margin facts from the local DB, and the DB is refreshed FIRST so it can never be stale. Follow the shared Sync-First + DB-Read pattern. Minimum for this skill (positions + balances into the balances table):
uv run python -m src.integrations.snaptrade.sync_db # or: refresh_all
Completion criterion: the balances table carries this run's synced_at before any margin number is read.
Use this skill when:
Static private assumptions come from .env (see .env.example). Current portfolio facts come from the local DB balances snapshot (refreshed sync-first in Step 0), then src/analysis/margin_metrics.py derives ratios/costs at runtime. Do not hardcode personal numbers in this skill. Fallbacks: --source snaptrade reads the API live, --source csv reads the legacy Fidelity balances CSV.
.env valuesFG_STRATEGY_START_DATEFG_MARGIN_INTEREST_RATE, FG_MARGIN_INTEREST_RATE_DECIMALFG_MARGIN_JUMP_ALERT_THRESHOLDFG_CURRENT_MONTHLY_DRAW, FG_MONTH6_DRAW_TARGET, FG_MONTH12_DRAW_TARGET, FG_MONTH18_DRAW_TARGETFG_BUSINESS_INCOME_MONTHLY, FG_BUSINESS_INJECTION_RED, FG_BUSINESS_INJECTION_CRITICAL.env values: portfolio value, margin balance, interest cost, dividend income, coverage ratio, and portfolio-to-margin ratio must be read/calculated at runtime.After Step 0's refresh, run uv run python -m src.analysis.margin_metrics --pretty. It loads .env, reads the latest balances row from family_office.db (the db source is the default), and emits current JSON metrics. Fallbacks if needed: --source snaptrade (live API) or --source csv (latest Balances_for_Account_*.csv).
Source: the balances table, written by the Step 0 sync from the enabled+routed SnapTrade account in config/snaptrade-accounts.yaml (enabled: true, role set). Requires SNAPTRADE_* keys in .env for the refresh.
Key JSON fields the tool emits:
portfolio_value โ net account equity (account_equity) โ Portfolio Valuemargin_balance โ derived margin debt (gross market value minus net equity) โ Margin Balancemonthly_interest_cost โ Balance ร Rate รท 12 (the primary interest figure)margin_interest_accrued_this_month โ null on the DB and SnapTrade paths (the broker does not expose accrued interest; it is only present via --source csv)Calculations:
Rule: If new margin balance > previous balance + ${FG_MARGIN_JUMP_ALERT_THRESHOLD}, STOP
Reason: Large draws should be intentional per margin-living strategy
Example:
Previous: {live.margin_balance}
Current: {example.margin_current} (+{derived.margin_increase}) โ ๐จ ALERT - Confirm intentional draw
Action:
There is nowhere to write an entry: balances is a current-state table keyed on
account_id, so each sync overwrites the prior row and no ledger accumulates.
Report the snapshot in the response instead.
date +"%Y-%m-%d")margin_debt from the balances rowmargin_debt ร ${FG_MARGIN_INTEREST_RATE} รท 12
monthly_interest_cost ร 12
Sum type = 'DIVIDEND' rows in transactions for the trailing month. See the
dividend-tracking skill; do not recompute its aggregation differently here.
monthly_dividend_income รท monthly_interest_cost
Guard the zero case: when margin_debt is 0 there is no interest to cover, so
report coverage as not-applicable rather than dividing.
= Total account value รท Margin Balance
Example: {live.portfolio_value} รท {live.margin_balance} = {derived.portfolio_margin_ratio} ๐ข๐ข๐ข
Safety Thresholds:
Current monthly draw: ${FG_CURRENT_MONTHLY_DRAW} (fixed expenses only)
Target: Start with ${FG_CURRENT_MONTHLY_DRAW}, scale to ${FG_MONTH6_DRAW_TARGET}, ${FG_MONTH12_DRAW_TARGET}, ${FG_MONTH18_DRAW_TARGET} based on data
Strategy Start Date: ${FG_STRATEGY_START_DATE}
Calculate months elapsed:
import os
from datetime import datetime
start = datetime.fromisoformat(os.getenv("FG_STRATEGY_START_DATE"))
current = datetime.now()
months_elapsed = (current - start).days // 30
๐ MONTH 6 MILESTONE CHECK:
โ
Dividends: {live.monthly_dividend_income}/month (need ${FG_MONTH6_DIVIDEND_MINIMUM})
โ
Portfolio-to-Margin Ratio: {derived.portfolio_margin_ratio} (need 4:1+)
โ
Dividend Growth: On track
๐ฏ RECOMMENDATION: Scale margin draw to ${FG_MONTH6_DRAW_TARGET}/month (add mortgage)
- Current: ${FG_CURRENT_MONTHLY_DRAW} (fixed expenses only)
- New: ${FG_MONTH6_DRAW_TARGET} (fixed + mortgage)
- Safety margin: Excellent
๐ MONTH 12 BREAK-EVEN CHECK:
Expected Dividends: ${FG_MONTH12_DIVIDEND_TARGET}/month (goal: break-even with margin interest)
โ
IF achieved: Consider scaling to ${FG_MONTH12_DRAW_TARGET}/month (add some variable expenses)
โ ๏ธ IF not: Hold at ${FG_MONTH6_DRAW_TARGET}, assess strategy
๐ MONTH 18 MATURE STRATEGY CHECK:
Expected Dividends: ${FG_MONTH18_DIVIDEND_TARGET}/month
Expected Margin: Declining (dividends paying down debt)
โ
IF achieved: Consider scaling to ${FG_MONTH18_DRAW_TARGET}/month (most variable expenses)
โ ๏ธ IF not: Hold current level, reassess timeline
Generate alerts based on conditions:
โ
Ratio > 4:1 AND dividends covering interest
Status: On track, continue per strategy
โ ๏ธ Ratio 3.5-4:1 OR dividend coverage declining
Action: Pause scaling, monitor weekly
๐จ Ratio < 3:1 OR dividend cuts detected
Action: STOP draws, inject ${FG_BUSINESS_INJECTION_RED} business income
โ Ratio < 2.5:1 OR margin call risk
Action: STOP draws, inject ${FG_BUSINESS_INJECTION_CRITICAL} business income, consider selling hedge (SQQQ)
family_office.db is written by the sync CLIs alone. Never hand-edit rows to
make a metric look right; fix the sync that wrote the bad row instead.
Core Principle: Confidence-based scaling, not time-based mandates
Decision Framework:
Available: ${FG_BUSINESS_INCOME_MONTHLY}/month from business operations
Usage Scenarios:
Current Philosophy: Insurance policy only, not active strategy component
Portfolio Value: {live.portfolio_value}
Margin Balance: {live.margin_balance}
Ratio: {derived.portfolio_margin_ratio} ๐ข๐ข๐ข
Monthly Interest: {derived.monthly_interest_cost}
Dividend Income: {live.monthly_dividend_income}
Coverage: {derived.coverage_ratio} ๐ข
Status: Excellent - building foundation
Portfolio Value: {projection.month6_portfolio_value} (projected with W2 contributions)
Margin Balance: {projection.month6_margin_balance} (scaled to ${FG_MONTH6_DRAW_TARGET}/month draw)
Ratio: {projection.month6_portfolio_margin_ratio} ๐ข
Monthly Interest: {projection.month6_monthly_interest_cost}
Dividend Income: ${FG_CURRENT_MONTHLY_DRAW} (projected)
Coverage: {projection.month6_coverage_ratio} ๐ข
Status: Healthy - on track for break-even
Portfolio Value: {projection.month15_portfolio_value}
Margin Balance: {projection.month15_margin_balance} (scaled to ${FG_MONTH12_DRAW_TARGET}/month draw)
Ratio: {projection.month15_portfolio_margin_ratio} ๐ข
Monthly Interest: {projection.month15_monthly_interest_cost}
Dividend Income: {projection.month15_monthly_dividend_income}
Coverage: {projection.month15_coverage_ratio} ๐ข
Status: Break-even achieved, dividends > interest
Margin balance, buying power, and maintenance requirement come from the balances table in family_office.db, refreshed sync-first (Step 0). The Margin Dashboard sheet was retired 2026-07-31.
The balances columns are account_id, currency, settled_cash,
buying_power, account_equity, gross_market_value, margin_debt, and
synced_at. There is no maintenance_excess column; maintenance headroom is
derived, not stored.
sqlite3 family_office.db \
"SELECT synced_at, account_id, settled_cash, buying_power, account_equity, margin_debt
FROM balances ORDER BY synced_at DESC;"
balances is keyed on account_id, so it holds one current row per account and
no history. Read synced_at to confirm the row belongs to this run's refresh
before deriving anything from it.
Cash-management accounts sync through SimpleFIN into bank_transactions, deliberately outside the brokerage balances table, so they never distort the portfolio-to-margin ratio.
For complete strategy details, see:
strategies/active/margin-living-master-strategy.mdstrategies/active/portfolio-master-strategy.mduser-profile.yamlconfig/snaptrade-accounts.yamlBefore reporting margin metrics:
config/snaptrade-accounts.yaml and SNAPTRADE_* keys are in .envDATABASE_URL is set in .envbalances row carries this run's synced_atdate commandEducational purposes only. Not investment advice. Margin borrowing carries risk of loss exceeding your deposit, and a margin call can force liquidation at unfavourable prices. Consult licensed financial and tax professionals before acting.
Trigger: User asks to sync/refresh margin from SnapTrade
Agent workflow:
Skill Type: Domain (workflow guidance) Enforcement: BLOCK (financial risk critical) Priority: Critical Line Count: < 400 (following 500-line rule) โ