Asteria Investment Office — Reusable Task-Solving Procedure
1. Workflow Rules
1.1 Always start from the API, not the local payload
Local payloads (desk requests, meeting memos, committee packets) provide task context only — the opportunity-set names requested, the portfolio id, the quarter, the trade size. Stale snapshots, stale marks, and stale local notes must be overridden with current API data.
1.2 Data-precedence baseline
Unless the local payload has a date newer than the API as_of_date (which it never will in this environment), the API is authoritative. Use "data_precedence": "current_environment_over_stale_payload" as the default answer.
1.3 Standard call sequence
GET /api/policies— policy thresholds, constraint bands, correlation thresholds, conviction/view-score mapping.GET /api/portfolios/<portfolio_id>— current holdings, total market value, constraint policy id.- Domain-specific endpoints:
- Credit / fixed-income:
/api/instruments/bonds,/api/issuers,/api/market/energy - Equity / correlation:
/api/indices,/api/index-levels - Allocation:
/api/allocation/opportunity-sets,/api/allocation/prior-views,/api/macro-signals
- Credit / fixed-income:
/api/catalogis only needed to confirm available IDs.
1.4 Task-type dispatch
- Credit trade strategy (portfolio with
POL_CREDIT_DEFAULT): bonds + issuers + energy market + portfolio holdings → select BUY tickets, compute post-trade metrics, check constraints. - Correlation review (portfolio with
POL_CORRELATION_DEFAULT): index levels → Pearson correlations → extreme pairs, concentration, diversification candidates. - Allocation view refresh (CIO desk, no single portfolio): opportunity-set taxonomy + macro signals + prior views + policy → view/change/conviction/rationale rows + risk overlay.
- FI risk rebalance (portfolio with
POL_CREDIT_RISK_REDUCTION): portfolio + bonds + issuers → SELL/BUY trades reducing HY + watchlist while keeping duration in band. - Multi-asset committee (portfolio with
POL_MULTI_ASSET_DEFAULTorPOL_MULTI_ASSET_RISK): correlation review (subset of indices) + allocation views (subset of opportunity sets) → linked output.
2. API/Data Usage Habits
2.1 Key entity relationships
bond.instrument_id→bond.issuer_id→issuer.issuer_idportfolio.holdings[].instrument_id→bond.instrument_id(orindex_idfor equity sleeves)bond.rating_bucket∈ {IG,HY}.issuer.rating_bucketmatches but may differ in nuance — use bond-levelrating_bucketfor HY/IG classification.issuer.watchlist(boolean) is the authoritative watchlist flag. Bonds taggedWATCHLIST_RISKinrecommended_theme_tagsare a secondary signal.bond.candidate(boolean) —falsemeans the bond is already held and should not be double-counted as a new buy unless explicitly instructed.
2.2 Policy constraints lookup
Read /api/policies once. The response is keyed by policy category:
allocation_mapping— view-score thresholds and conviction thresholds.credit_default—max_hy_allocation_pct,duration_band_years,issuer_concentration_limit_pct,subsector_min_count_for_diversified.credit_risk_reduction— same fields +target_hy_reduction_pct.correlation—correlation_high_threshold(0.8),correlation_low_threshold(0.2).multi_asset/multi_asset_risk— composite policies that reference the above.
The portfolio object's constraint_policy_id (or constraints.policy_id) tells you which policy to apply.
2.3 Index-levels endpoint
GET /api/index-levels returns all indices. Each index has 12 monthly levels from 2025-05-30 through 2026-04-30 inclusive. Levels are already sorted chronologically. The indices endpoint gives metadata: level_start_date, level_end_date, currency, frequency.
2.4 Macro-signals and prior-views quarter filtering
Both return all quarters. Filter:
- Macro signals:
quarter == "<target_quarter>"(e.g.,"Q2_2026") - Prior views:
quarter == "<target_quarter>"ANDprevious_quarter == "<prior_quarter>"(e.g.,Q2_2026withQ1_2026as previous). These prior-view records tell you what the Q1→Q2 view WAS.
2.5 Energy market signals
Each signal has signal_id, score (float, signed), direction (descriptive), commodity, summary. Use these to theme the trade selection. Positive scores on LNG (0.72) and gas (0.46) support gas/LNG-linked bonds. Negative on refining (-0.41) warns away from refiners.
3. Calculation Procedures
3.1 Pearson correlation of monthly simple returns
Given index levels L_0, L_1, ..., L_n (n+1 levels → n returns):
r_t = (L_t - L_{t-1}) / L_{t-1} for t = 1..n
Then Pearson:
ρ = Σ(r_i - r̄)(s_i - s̄) / sqrt(Σ(r_i - r̄)² × Σ(s_i - s̄)²)
- Use all levels within the window (start_date through end_date, both inclusive).
return_observations= number of levels − 1 = 11 for a full 12-month window.- Round correlations to 3 decimal places.
- Do NOT use log returns. Do NOT annualize.
3.2 Portfolio-level weighted metrics
Pre-trade (current):
hy_allocation_pct = Σ(mv of HY-rated holdings) / total_mv × 100
weighted_modified_duration = Σ(holding_mv × instrument_duration) / total_mv
weighted_yield_to_maturity = Σ(holding_mv × instrument_ytm) / total_mv
Post-trade: Start with current holdings. Add BUY ticket notional amounts; remove SELL ticket amounts from both the numerator and denominator. Recompute.
HY reduction (risk rebalance):
hy_reduction_pct_points = pre_trade_hy_pct − post_trade_hy_pct
Watchlist exposure:
Sum market values of holdings whose issuer has watchlist == true.
3.3 Active allocation view from macro signal score
From policy allocation_mapping:
OWif score ≥ 0.35UWif score ≤ −0.35Notherwise (i.e., −0.35 < score < 0.35)
Conviction:
HIGHif |score| ≥ 0.70MEDIUMif 0.35 ≤ |score| < 0.70LOWif |score| < 0.35
Change vs prior quarter:
Compare the current view (derived from signal score) against the prior view from the prior-views API (Q1_2026 records with quarter: "Q2_2026"):
UP— view moved in the positive direction (N→OW, UW→N, UW→OW)DOWN— view moved in the negative direction (N→UW, OW→N, OW→UW)UNCHANGED— view stayed the same
Rationale code: Taken directly from the macro-signal record's rationale_code field. Do not invent rationale codes.
3.4 Constraint checks
HY cap: post_trade_hy_allocation_pct ≤ max_hy_allocation_pct (20%).
Duration band: duration_band_years[0] ≤ weighted_modified_duration ≤ duration_band_years[1] (3.0–5.0).
Issuer diversification (selected): The newly selected BUY tickets have distinct issuers. In the credit trade context (selected_issuer_diversification_pass), check that the two selected bonds are from different issuers.
Subsector diversification (selected): The newly selected BUY tickets belong to different subsectors. subsector_min_count_for_diversified = 2, so the two selected bonds must map to ≥ 2 distinct subsectors.
Watchlist avoidance: No BUY ticket's issuer has watchlist == true. Also exclude bonds whose recommended_theme_tags include "WATCHLIST_RISK".
Target HY reduction met (risk rebalance): hy_reduction_pct_points ≥ target_hy_reduction_pct (4.0 pp for POL_CREDIT_RISK_REDUCTION).
3.5 Correlation concentration analysis
Concentration (china_asia_dependence): If the China–Asia Pacific ex Japan correlation exceeds the
correlation_high_threshold(0.8) and China is in the portfolio as a dedicated sleeve, flagchina_asia_dependence_flag: truewithprimary_code: "CHINA_ASIA_DEPENDENCE"andhigh_threshold_breached: true.Extreme pairs:
highest_positive= the pair with the maximum Pearson correlation.lowest= the pair with the minimum Pearson correlation (most negative). Break ties by alphabetical order of the pair_id list.Diversification candidates: Among
IDX_EM_EX_CHINA,IDX_INDIA,IDX_LATAM, select those with below-average correlation to the portfolio's concentration-risk indices. In practice, identify indices with low or negative correlations vs China/EM.
4. Output-Field Conventions
4.1 Dates
- Use
YYYY-MM-DDformat. as_of_date: use the API portfolio'sas_of_date(or the policiesas_of_dateif no portfolio). This is consistently2026-05-29in the current environment.- Review windows: use the
review_windowfrom the correlation policy or the local request's window boundaries.
4.2 Sort orders
- Trade tickets: Sort by
action(SELL before BUY), then byinstrument_idascending within each action group. - Trade package (BUY only): Sort ascending by
instrument_id. - Index/pair lists: Sort alphabetically by index id.
- Pair identifiers within a pair: Always sort alphabetically.
- Allocation view rows: Follow the order in the request payload's
focus_opportunity_setslist. - Sleeve actions: Sort ascending by sleeve/opportunity_set name.
- Diversification candidates list: Sort ascending alphabetically.
- Watchlist sell IDs: Sort ascending by instrument_id.
4.3 Numeric precision
Match the precision declared in each answer template:
notional_usd_m/quantity_usd_m: 1 decimaltotal_market_value_usd_m: 2 decimalshy_allocation_pct: 2 decimalsweighted_modified_duration_years: 2 decimalsweighted_yield_to_maturity_pct: 2 decimalspost_trade_hy_allocation_pct: 2 decimalspost_trade_duration_years: 2 decimalshy_reduction_pct_points: 2 decimalspost_trade_watchlist_exposure_usd_m: 1 decimalcorrelation: 3 decimalssignal_score: 3 decimals
4.4 Enum values
Use EXACT string values from the answer template's allowed_values lists. Common enums:
- Views:
"UW","N","OW" - Change:
"UP","DOWN","UNCHANGED" - Conviction:
"LOW","MEDIUM","HIGH" - Actions:
"BUY","SELL","trim","add","hold","hedge","monitor","rotate" - Booleans are JSON
true/false, not strings.
4.5 Envelope
Return only JSON. No markdown fences, no narrative. The JSON must contain every required key from the answer template.
5. Common Pitfalls
Using stale local data instead of API. The local payload's holding snapshot, stale marks, or prior-week shortlists are intake context — the API is the current book of record.
Confusing
rating_bucketbetween bond and issuer levels. Use the bond'srating_bucketfor HY/IG classification in portfolio metrics. The issuer-levelrating_bucketmay differ.Watchlist check on bond tags, not issuer. Always cross-reference
issuer.watchlist. A bond may not haveWATCHLIST_RISKin tags even if the issuer is watchlisted (though in this environment they are consistent, the issuer is authoritative).Using log returns for correlation. The task spec says Pearson on simple monthly returns. Log returns produce slightly different correlations.
Miscounting return observations. 12 monthly levels → 11 return observations (consecutive pairs). Don't report 12.
Wrong prior quarter for view changes. For Q2_2026 target, the prior is Q1_2026. The
/api/allocation/prior-viewsrecords withquarter: "Q2_2026"andprevious_quarter: "Q1_2026"give the prior view. Don't look at Q1_2026 quarter records directly.Forgetting the correlation policy thresholds. The
high_threshold(0.8) andlow_threshold(0.2) are in/api/policiesundercorrelation. Use them for concentration/diversification flags — don't hardcode.Not checking BUY candidates against the constraint policy. Every BUY must be:
candidate == true, issuerwatchlist == false, and (for energy tasks)energy_linked == trueunless the task explicitly widens the universe.Duration band misapplication. The band
[3.0, 5.0]means 3.0 ≤ duration ≤ 5.0. Both endpoints are inclusive.Pair-id alphabetization inside pairs.
["IDX_CHINA", "IDX_EM"]not["IDX_EM", "IDX_CHINA"]even if EM is mentioned first in the task.Risk overlay ordering. The
rationale_codeslist in the risk overlay must be in business priority order, highest priority first. Derive priority from signal score magnitude and policy impact.Trade sizing mismatch. For train_001-style tasks: the total and per-ticket notional must sum exactly to the requested amounts (e.g., $8.0M total, $4.0M each). For train_004-style rotations: sell and buy amounts need not match — the goal is meeting the risk constraints, not preserving MV.
Conviction vs view confusion. Conviction is about the strength of the signal (|score| magnitude). View is about the direction (sign of score vs thresholds). A HIGH-conviction OW is possible (score ≥ 0.70); a LOW-conviction OW is also possible (0.35 ≤ score < 0.70 but not HIGH).
Risk overlay vs allocation views. The risk overlay (
overlay_code+primary_action) is a portfolio-level recommendation separate from the individual allocation rows. Its rationale_codes should be the highest-priority rationale codes from the most material allocation views.