@riskmodels/mcp 1.0.1 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/INSTALL.md +3 -2
- package/NPM_REPUBLISH_CHECKLIST.md +221 -0
- package/PUBLISHING.md +83 -0
- package/README.md +20 -3
- package/data/benchmark_master.json +68 -0
- package/data/capabilities.json +729 -4
- package/data/etf_master.json +304 -0
- package/data/openapi.json +11060 -3722
- package/data/schema-paths.json +2 -0
- package/data/schemas/canonical-snapshot-v1.json +46 -0
- package/data/schemas/decompose-v1.json +132 -0
- package/data/schemas/hedge-levels-v1.json +68 -0
- package/dist/lib/mcp/tools/riskmodels-tools.d.ts +5 -3
- package/dist/lib/mcp/tools/riskmodels-tools.js +77 -4
- package/dist/mcp/src/server.js +55 -0
- package/package.json +4 -3
- package/server.json +18 -0
- package/src/server.ts +64 -0
package/data/capabilities.json
CHANGED
|
@@ -73,7 +73,7 @@
|
|
|
73
73
|
{
|
|
74
74
|
"id": "metrics",
|
|
75
75
|
"name": "Latest Risk Metrics",
|
|
76
|
-
"description": "Fetch latest hedge ratios (HR), explained risk (ER), volatility,
|
|
76
|
+
"description": "Fetch latest hedge ratios (HR), explained risk (ER), volatility, stock variance, plus the Lstar-dispatched lstar_rr (residual return at the level Lstar picked) and lstar_level (1/2/3/null) for a ticker from security_history (V3)",
|
|
77
77
|
"endpoint": "/api/metrics/{ticker}",
|
|
78
78
|
"method": "GET",
|
|
79
79
|
"parameters": {
|
|
@@ -506,7 +506,7 @@
|
|
|
506
506
|
{
|
|
507
507
|
"id": "metrics-snapshot",
|
|
508
508
|
"name": "Metrics Snapshot",
|
|
509
|
-
"description": "Latest risk metrics snapshot for a single ticker (volatility, hedge ratios, explained risk, hierarchical regression betas l1_mkt_beta/l2_sec_beta/l3_sub_beta,
|
|
509
|
+
"description": "Latest risk metrics snapshot for a single ticker (volatility, hedge ratios, explained risk, hierarchical regression betas l1_mkt_beta/l2_sec_beta/l3_sub_beta, combined factor returns / residual returns at L1/L2/L3, and the Lstar-dispatched pair lstar_rr + lstar_level — 1/2/3 for the level Lstar picked, null when no recommendation — at the canonical 1% marginal-ER threshold)",
|
|
510
510
|
"endpoint": "/api/metrics",
|
|
511
511
|
"method": "GET",
|
|
512
512
|
"parameters": {
|
|
@@ -573,6 +573,327 @@
|
|
|
573
573
|
},
|
|
574
574
|
"tags": ["risk", "decomposition", "l3"]
|
|
575
575
|
},
|
|
576
|
+
{
|
|
577
|
+
"id": "returns-decomposition",
|
|
578
|
+
"name": "Returns Decomposition",
|
|
579
|
+
"description": "Daily gross + L1/L2/L3 factor/combined/residual returns from ds_erm3_returns; optional Lstar dispatch",
|
|
580
|
+
"endpoint": "/api/returns-decomposition",
|
|
581
|
+
"method": "GET",
|
|
582
|
+
"parameters": {
|
|
583
|
+
"ticker": {
|
|
584
|
+
"type": "string",
|
|
585
|
+
"required": true,
|
|
586
|
+
"description": "Stock ticker symbol"
|
|
587
|
+
},
|
|
588
|
+
"market_factor_etf": {
|
|
589
|
+
"type": "string",
|
|
590
|
+
"required": false,
|
|
591
|
+
"description": "Market factor ETF",
|
|
592
|
+
"default": "SPY"
|
|
593
|
+
},
|
|
594
|
+
"years": {
|
|
595
|
+
"type": "integer",
|
|
596
|
+
"required": false,
|
|
597
|
+
"description": "Calendar years of daily history",
|
|
598
|
+
"default": 1
|
|
599
|
+
},
|
|
600
|
+
"include_lstar": {
|
|
601
|
+
"type": "boolean",
|
|
602
|
+
"required": false,
|
|
603
|
+
"description": "Include lstar and lstar_residual_return arrays",
|
|
604
|
+
"default": false
|
|
605
|
+
},
|
|
606
|
+
"threshold": {
|
|
607
|
+
"type": "number",
|
|
608
|
+
"required": false,
|
|
609
|
+
"description": "Marginal ER threshold for Lstar derivation",
|
|
610
|
+
"default": 0.01
|
|
611
|
+
}
|
|
612
|
+
},
|
|
613
|
+
"pricing": {
|
|
614
|
+
"model": "per_request",
|
|
615
|
+
"cost_usd": 0.02,
|
|
616
|
+
"currency": "USD",
|
|
617
|
+
"billing_code": "returns_decomposition_v1"
|
|
618
|
+
},
|
|
619
|
+
"performance": {
|
|
620
|
+
"avg_latency_ms": 140,
|
|
621
|
+
"p95_latency_ms": 240,
|
|
622
|
+
"availability_sla": 99.9,
|
|
623
|
+
"rate_limit_per_minute": 60
|
|
624
|
+
},
|
|
625
|
+
"confidence": {
|
|
626
|
+
"data_quality_score": 0.99,
|
|
627
|
+
"update_frequency": "daily",
|
|
628
|
+
"sources": ["ds_erm3_returns", "security_history"]
|
|
629
|
+
},
|
|
630
|
+
"tags": ["returns", "decomposition", "lstar", "macro"]
|
|
631
|
+
},
|
|
632
|
+
{
|
|
633
|
+
"id": "industry-panel",
|
|
634
|
+
"name": "Industry Panel",
|
|
635
|
+
"description": "Industry peer β cross-section from ds_erm3_industry (beta_mean, beta_variance, n_companies by industry code and level)",
|
|
636
|
+
"endpoint": "/api/industry-panel",
|
|
637
|
+
"method": "GET",
|
|
638
|
+
"parameters": {
|
|
639
|
+
"market_factor_etf": {
|
|
640
|
+
"type": "string",
|
|
641
|
+
"required": false,
|
|
642
|
+
"description": "Market factor ETF",
|
|
643
|
+
"default": "SPY"
|
|
644
|
+
},
|
|
645
|
+
"teo": {
|
|
646
|
+
"type": "string",
|
|
647
|
+
"required": false,
|
|
648
|
+
"description": "Observation date YYYY-MM-DD (default latest teo)"
|
|
649
|
+
},
|
|
650
|
+
"level": {
|
|
651
|
+
"type": "string",
|
|
652
|
+
"required": false,
|
|
653
|
+
"description": "Optional cascade level filter",
|
|
654
|
+
"enum": ["market", "sector", "subsector"]
|
|
655
|
+
},
|
|
656
|
+
"min_peers": {
|
|
657
|
+
"type": "integer",
|
|
658
|
+
"required": false,
|
|
659
|
+
"description": "Minimum n_companies filter"
|
|
660
|
+
}
|
|
661
|
+
},
|
|
662
|
+
"pricing": {
|
|
663
|
+
"model": "per_request",
|
|
664
|
+
"cost_usd": 0.02,
|
|
665
|
+
"currency": "USD",
|
|
666
|
+
"billing_code": "industry_panel_v1"
|
|
667
|
+
},
|
|
668
|
+
"performance": {
|
|
669
|
+
"avg_latency_ms": 120,
|
|
670
|
+
"p95_latency_ms": 200,
|
|
671
|
+
"availability_sla": 99.9,
|
|
672
|
+
"rate_limit_per_minute": 60
|
|
673
|
+
},
|
|
674
|
+
"confidence": {
|
|
675
|
+
"data_quality_score": 0.99,
|
|
676
|
+
"update_frequency": "daily",
|
|
677
|
+
"sources": ["ds_erm3_industry"]
|
|
678
|
+
},
|
|
679
|
+
"tags": ["industry", "macro", "cross-section", "stat-arb"]
|
|
680
|
+
},
|
|
681
|
+
{
|
|
682
|
+
"id": "rankings-screen",
|
|
683
|
+
"name": "Rankings Screen",
|
|
684
|
+
"description": "Full cross-section rank screen from ds_rankings zarr: server-side percentile, decile, and sector ETF filters over the entire universe at one teo (default latest). Returns up to 500 names sorted by rank_ordinal (1 = best). rank_percentile 100 = best.",
|
|
685
|
+
"endpoint": "/api/rankings/screen",
|
|
686
|
+
"method": "POST",
|
|
687
|
+
"parameters": {
|
|
688
|
+
"metric": {
|
|
689
|
+
"type": "string",
|
|
690
|
+
"required": true,
|
|
691
|
+
"description": "Metric: mkt_cap, gross_return, sector_residual, subsector_residual, er_l1, er_l2, er_l3"
|
|
692
|
+
},
|
|
693
|
+
"cohort": {
|
|
694
|
+
"type": "string",
|
|
695
|
+
"required": true,
|
|
696
|
+
"description": "Cohort: universe, sector, subsector"
|
|
697
|
+
},
|
|
698
|
+
"window": {
|
|
699
|
+
"type": "string",
|
|
700
|
+
"required": true,
|
|
701
|
+
"description": "Window: 1d, 21d, 63d, 252d"
|
|
702
|
+
},
|
|
703
|
+
"as_of": {
|
|
704
|
+
"type": "string",
|
|
705
|
+
"required": false,
|
|
706
|
+
"description": "Observation date YYYY-MM-DD (default latest teo)"
|
|
707
|
+
},
|
|
708
|
+
"min_percentile": {
|
|
709
|
+
"type": "number",
|
|
710
|
+
"required": false,
|
|
711
|
+
"description": "Minimum rank_percentile inclusive (100 = best)"
|
|
712
|
+
},
|
|
713
|
+
"decile": {
|
|
714
|
+
"type": "integer",
|
|
715
|
+
"required": false,
|
|
716
|
+
"description": "Decile bucket 1=best (top 10%), through 10"
|
|
717
|
+
},
|
|
718
|
+
"sector_filter": {
|
|
719
|
+
"type": "string",
|
|
720
|
+
"required": false,
|
|
721
|
+
"description": "Sector ETF ticker filter (e.g. XLK) on symbols.sector_etf"
|
|
722
|
+
},
|
|
723
|
+
"limit": {
|
|
724
|
+
"type": "integer",
|
|
725
|
+
"required": false,
|
|
726
|
+
"description": "Max rows after filter (1–500, default 100)",
|
|
727
|
+
"default": 100
|
|
728
|
+
}
|
|
729
|
+
},
|
|
730
|
+
"pricing": {
|
|
731
|
+
"model": "per_request",
|
|
732
|
+
"tier": "premium",
|
|
733
|
+
"cost_usd": 0.05,
|
|
734
|
+
"currency": "USD",
|
|
735
|
+
"billing_code": "rankings_screen_v1"
|
|
736
|
+
},
|
|
737
|
+
"performance": {
|
|
738
|
+
"avg_latency_ms": 180,
|
|
739
|
+
"p95_latency_ms": 350,
|
|
740
|
+
"availability_sla": 99.9,
|
|
741
|
+
"rate_limit_per_minute": 60
|
|
742
|
+
},
|
|
743
|
+
"confidence": {
|
|
744
|
+
"data_quality_score": 0.98,
|
|
745
|
+
"update_frequency": "daily",
|
|
746
|
+
"sources": ["ds_rankings"]
|
|
747
|
+
},
|
|
748
|
+
"tags": ["rankings", "cross-sectional", "screen", "percentile"]
|
|
749
|
+
},
|
|
750
|
+
{
|
|
751
|
+
"id": "batch-lstar",
|
|
752
|
+
"name": "Batch Lstar Residual Returns",
|
|
753
|
+
"description": "Up to 100 tickers: per-date Lstar level (L1/L2/L3) with dispatched hedge ratios and Lstar-dispatched daily residual return. Same selection rule as GET /lstar.",
|
|
754
|
+
"endpoint": "/api/batch/lstar",
|
|
755
|
+
"method": "POST",
|
|
756
|
+
"parameters": {
|
|
757
|
+
"tickers": {
|
|
758
|
+
"type": "array",
|
|
759
|
+
"required": true,
|
|
760
|
+
"description": "Stock ticker symbols (max 100)",
|
|
761
|
+
"items": { "type": "string" }
|
|
762
|
+
},
|
|
763
|
+
"market_factor_etf": {
|
|
764
|
+
"type": "string",
|
|
765
|
+
"required": false,
|
|
766
|
+
"description": "Market factor ETF",
|
|
767
|
+
"default": "SPY"
|
|
768
|
+
},
|
|
769
|
+
"years": {
|
|
770
|
+
"type": "integer",
|
|
771
|
+
"required": false,
|
|
772
|
+
"description": "Calendar years of daily history",
|
|
773
|
+
"default": 1
|
|
774
|
+
},
|
|
775
|
+
"threshold": {
|
|
776
|
+
"type": "number",
|
|
777
|
+
"required": false,
|
|
778
|
+
"description": "Marginal-ER threshold for Lstar selection (default 1%)",
|
|
779
|
+
"default": 0.01
|
|
780
|
+
},
|
|
781
|
+
"format": {
|
|
782
|
+
"type": "string",
|
|
783
|
+
"required": false,
|
|
784
|
+
"description": "json, parquet, or csv long table",
|
|
785
|
+
"default": "json",
|
|
786
|
+
"enum": ["json", "parquet", "csv"]
|
|
787
|
+
}
|
|
788
|
+
},
|
|
789
|
+
"pricing": {
|
|
790
|
+
"model": "per_position",
|
|
791
|
+
"tier": "premium",
|
|
792
|
+
"cost_usd": 0.005,
|
|
793
|
+
"currency": "USD",
|
|
794
|
+
"min_charge": 0.01,
|
|
795
|
+
"billing_code": "batch_lstar_v1"
|
|
796
|
+
},
|
|
797
|
+
"performance": {
|
|
798
|
+
"avg_latency_ms": 350,
|
|
799
|
+
"p95_latency_ms": 800,
|
|
800
|
+
"availability_sla": 99.9,
|
|
801
|
+
"rate_limit_per_minute": 20
|
|
802
|
+
},
|
|
803
|
+
"confidence": {
|
|
804
|
+
"data_quality_score": 0.99,
|
|
805
|
+
"update_frequency": "daily",
|
|
806
|
+
"sources": ["erm3_models", "security_history"]
|
|
807
|
+
},
|
|
808
|
+
"tags": ["risk", "decomposition", "lstar", "batch", "macro", "stat-arb"]
|
|
809
|
+
},
|
|
810
|
+
{
|
|
811
|
+
"id": "residual-signal-basket",
|
|
812
|
+
"name": "Residual Mean-Reversion Basket",
|
|
813
|
+
"description": "Aggregate the L3 residual mean-reversion signal across a user-defined basket of up to 500 tickers. Returns the weighted aggregate of residual_z_5d / signal_strength / industry_percentile / l3_subsector_er + decile and quality-quintile histograms + per-member rows. Equal-weight default; optional weights[] aligned to tickers; optional signal_quality_min_quintile (1–5) gate. Tickers absent from ds_erm3_residual_signal are silently dropped (upstream mask is SSOT); coverage.missing_tickers surfaces what was dropped. Combo-input building block — NOT a standalone strategy.",
|
|
814
|
+
"endpoint": "/api/signals/residual-reversion/basket",
|
|
815
|
+
"method": "POST",
|
|
816
|
+
"parameters": {
|
|
817
|
+
"tickers": {
|
|
818
|
+
"type": "array",
|
|
819
|
+
"required": true,
|
|
820
|
+
"description": "Ticker symbols to aggregate (1–500).",
|
|
821
|
+
"items": { "type": "string" }
|
|
822
|
+
},
|
|
823
|
+
"weights": {
|
|
824
|
+
"type": "array",
|
|
825
|
+
"required": false,
|
|
826
|
+
"description": "Optional non-negative weights aligned 1:1 with tickers. Equal-weight when omitted.",
|
|
827
|
+
"items": { "type": "number" }
|
|
828
|
+
},
|
|
829
|
+
"signal_quality_min_quintile": {
|
|
830
|
+
"type": "integer",
|
|
831
|
+
"required": false,
|
|
832
|
+
"description": "Optional 1–5 gate on signal_quality_quintile (Phase B: Sharpe lifts from ~0.79 to ~1.28 at quintile 5)."
|
|
833
|
+
}
|
|
834
|
+
},
|
|
835
|
+
"pricing": {
|
|
836
|
+
"model": "per_request",
|
|
837
|
+
"tier": "premium",
|
|
838
|
+
"cost_usd": 0.02,
|
|
839
|
+
"currency": "USD",
|
|
840
|
+
"billing_code": "residual_signal_basket_v1"
|
|
841
|
+
},
|
|
842
|
+
"performance": {
|
|
843
|
+
"avg_latency_ms": 180,
|
|
844
|
+
"p95_latency_ms": 320,
|
|
845
|
+
"availability_sla": 99.9,
|
|
846
|
+
"rate_limit_per_minute": 60
|
|
847
|
+
},
|
|
848
|
+
"confidence": {
|
|
849
|
+
"data_quality_score": 0.99,
|
|
850
|
+
"update_frequency": "daily",
|
|
851
|
+
"sources": ["erm3_models"]
|
|
852
|
+
},
|
|
853
|
+
"tags": ["risk", "signal", "mean-reversion", "stat-arb", "basket", "factor"]
|
|
854
|
+
},
|
|
855
|
+
{
|
|
856
|
+
"id": "universe-members",
|
|
857
|
+
"name": "Universe Members",
|
|
858
|
+
"description": "Active membership of a named universe (uni_mc_50/500/1000/3000 or uni_dv_*) at a given teo (latest by default). Active = monthly universe_mask AND daily validity gate. Response carries members[{symbol, ticker}], counts{active, in_universe_mask, inactive_from_validity}, and a mask_as_of month-end stamp so callers can disambiguate mask-driven vs validity-driven membership changes. Foundational endpoint for cross-sectional workflows that need universe alignment without a local SDK cache.",
|
|
859
|
+
"endpoint": "/api/universe/{name}/members",
|
|
860
|
+
"method": "GET",
|
|
861
|
+
"parameters": {
|
|
862
|
+
"name": {
|
|
863
|
+
"type": "string",
|
|
864
|
+
"required": true,
|
|
865
|
+
"description": "Universe label from KNOWN_UNIVERSES.",
|
|
866
|
+
"enum": [
|
|
867
|
+
"uni_mc_50", "uni_mc_500", "uni_mc_1000", "uni_mc_3000",
|
|
868
|
+
"uni_dv_50", "uni_dv_500", "uni_dv_1000", "uni_dv_3000"
|
|
869
|
+
]
|
|
870
|
+
},
|
|
871
|
+
"teo": {
|
|
872
|
+
"type": "string",
|
|
873
|
+
"required": false,
|
|
874
|
+
"description": "Observation date YYYY-MM-DD (default latest teo)."
|
|
875
|
+
}
|
|
876
|
+
},
|
|
877
|
+
"pricing": {
|
|
878
|
+
"model": "per_request",
|
|
879
|
+
"tier": "baseline",
|
|
880
|
+
"cost_usd": 0.005,
|
|
881
|
+
"currency": "USD",
|
|
882
|
+
"billing_code": "universe_members_v1"
|
|
883
|
+
},
|
|
884
|
+
"performance": {
|
|
885
|
+
"avg_latency_ms": 90,
|
|
886
|
+
"p95_latency_ms": 180,
|
|
887
|
+
"availability_sla": 99.9,
|
|
888
|
+
"rate_limit_per_minute": 120
|
|
889
|
+
},
|
|
890
|
+
"confidence": {
|
|
891
|
+
"data_quality_score": 0.99,
|
|
892
|
+
"update_frequency": "daily",
|
|
893
|
+
"sources": ["ds_masks"]
|
|
894
|
+
},
|
|
895
|
+
"tags": ["universe", "membership", "foundational", "mask"]
|
|
896
|
+
},
|
|
576
897
|
{
|
|
577
898
|
"id": "portfolio-returns",
|
|
578
899
|
"name": "Portfolio Returns",
|
|
@@ -666,8 +987,8 @@
|
|
|
666
987
|
},
|
|
667
988
|
{
|
|
668
989
|
"id": "portfolio-risk-snapshot",
|
|
669
|
-
"name": "
|
|
670
|
-
"description": "
|
|
990
|
+
"name": "Snapshot — portfolio or ticker",
|
|
991
|
+
"description": "Canonical JSON snapshot (POST /api/snapshot) for either a weighted portfolio (type=portfolio) or a single ticker (type=ticker — shim over /metrics + /decompose). Returns L3 decomposition, hedge ratios, frozen-weight return attribution, cumulative return / drawdown, and risk summary in one unified shape. When the request includes `benchmark` (alias like 'SPY' / '70/30' or a BW-BENCH-* id), the response also carries `snapshot.benchmark_context_id` + `metadata.benchmark_context_id` — the resolved `BenchmarkContext` id (or null when unknown), chaseable via `/api/data/benchmark/{id}`. Also serves the bundled PDF/JSON via POST /api/portfolio/risk-snapshot. Bundled charge; internal DAL only.",
|
|
671
992
|
"endpoint": "/api/portfolio/risk-snapshot",
|
|
672
993
|
"method": "POST",
|
|
673
994
|
"parameters": {
|
|
@@ -920,5 +1241,409 @@
|
|
|
920
1241
|
}
|
|
921
1242
|
}
|
|
922
1243
|
]
|
|
1244
|
+
},
|
|
1245
|
+
{
|
|
1246
|
+
"id": "fund-snapshot-json",
|
|
1247
|
+
"name": "Fund Snapshot (JSON)",
|
|
1248
|
+
"description": "Composed JSON snapshot for a single mutual fund (Stage D.1). Bundles registry + latest metrics + top-25 holdings + L1/L2/L3 hedge + 12-month portfolio time series + cohort context (rank N of cohort_size). Matching server-rendered PDF is /funds/snapshot.pdf/{bw_fund_id}.",
|
|
1249
|
+
"endpoint": "/api/funds/snapshot/{bw_fund_id}",
|
|
1250
|
+
"method": "GET",
|
|
1251
|
+
"parameters": {
|
|
1252
|
+
"bw_fund_id": { "type": "string", "required": true, "description": "Funds_DAG canonical fund id (BW-FUND-{series_id})." }
|
|
1253
|
+
},
|
|
1254
|
+
"pricing": { "model": "per_request", "cost_usd": 0.01, "currency": "USD", "billing_code": "fund_snapshot_json_v1" },
|
|
1255
|
+
"tags": ["funds", "snapshot", "tearsheet"]
|
|
1256
|
+
},
|
|
1257
|
+
{
|
|
1258
|
+
"id": "fund-snapshot-pdf",
|
|
1259
|
+
"name": "Fund Snapshot (PDF)",
|
|
1260
|
+
"description": "Server-rendered F1 fund tearsheet PDF (Stage D.2.b). Same composition as /api/funds/snapshot/{bw_fund_id} (JSON), rendered via Playwright. Letter landscape, single page. Cached 24h per (user, bw_fund_id, report_date).",
|
|
1261
|
+
"endpoint": "/api/funds/snapshot.pdf/{bw_fund_id}",
|
|
1262
|
+
"method": "GET",
|
|
1263
|
+
"parameters": {
|
|
1264
|
+
"bw_fund_id": { "type": "string", "required": true, "description": "Funds_DAG canonical fund id (BW-FUND-{series_id})." }
|
|
1265
|
+
},
|
|
1266
|
+
"pricing": { "model": "per_request", "cost_usd": 0.25, "currency": "USD", "billing_code": "fund_snapshot_pdf_v1" },
|
|
1267
|
+
"tags": ["funds", "snapshot", "pdf", "tearsheet"]
|
|
1268
|
+
},
|
|
1269
|
+
{
|
|
1270
|
+
"id": "style-cohort-snapshot-json",
|
|
1271
|
+
"name": "Style Cohort Snapshot (JSON)",
|
|
1272
|
+
"description": "Composed JSON snapshot for a 9-box style cell (Stage D.1) — the differentiated wedge vs Morningstar. Bundles cohort metrics (EW + MV) + top-25 cohort holdings (MV) + 12-month cohort portfolio history (both weightings) + top-10 funds in cell + top-15 symbols in cell.",
|
|
1273
|
+
"endpoint": "/api/funds/style/{slug}/snapshot",
|
|
1274
|
+
"method": "GET",
|
|
1275
|
+
"parameters": {
|
|
1276
|
+
"slug": { "type": "string", "required": true, "description": "9-box style slug (large-blend, etc.)." }
|
|
1277
|
+
},
|
|
1278
|
+
"pricing": { "model": "per_request", "cost_usd": 0.005, "currency": "USD", "billing_code": "style_cohort_snapshot_json_v1" },
|
|
1279
|
+
"tags": ["funds", "snapshot", "cohort", "differentiated-wedge"]
|
|
1280
|
+
},
|
|
1281
|
+
{
|
|
1282
|
+
"id": "style-cohort-snapshot-pdf",
|
|
1283
|
+
"name": "Style Cohort Snapshot (PDF)",
|
|
1284
|
+
"description": "Server-rendered C1 cohort tearsheet PDF (Stage D.2.d). Same composition as /api/funds/style/{slug}/snapshot (JSON), rendered via Playwright. Letter landscape, single page. Cached 24h per (user, slug, report_date).",
|
|
1285
|
+
"endpoint": "/api/funds/style/{slug}/snapshot.pdf",
|
|
1286
|
+
"method": "GET",
|
|
1287
|
+
"parameters": {
|
|
1288
|
+
"slug": { "type": "string", "required": true, "description": "9-box style slug (large-blend, etc.)." }
|
|
1289
|
+
},
|
|
1290
|
+
"pricing": { "model": "per_request", "cost_usd": 0.10, "currency": "USD", "billing_code": "style_cohort_snapshot_pdf_v1" },
|
|
1291
|
+
"tags": ["funds", "snapshot", "cohort", "pdf", "differentiated-wedge"]
|
|
1292
|
+
},
|
|
1293
|
+
{
|
|
1294
|
+
"id": "filer-metrics",
|
|
1295
|
+
"name": "13F Filer Metrics",
|
|
1296
|
+
"description": "Latest knowledge-mode metrics for a single 13F filer — registry row (filer_type, aum_tier, n_funds_managed) + portfolio metrics (total_aum_usd, coverage_in_erm3, aum_in_erm3, n_holdings_active, effective_n, top10_weight_sum, dominant_9box, portfolio_style_hhi, is_modelable, portfolio_*_return + variance shares once D.8.22 populates). Reads public.filers + public.filer_portfolios_latest. Bitemporal lineage on response headers (X-Data-As-Of, X-Data-Filing-Date, X-Risk-Model-Version). Per-filer holdings + portfolio history live on GCS zarr and surface via /holdings + /portfolio. MASTER_BACKLOG D.8.8.",
|
|
1297
|
+
"endpoint": "/api/13f/filers/{bw_filer_id}",
|
|
1298
|
+
"method": "GET",
|
|
1299
|
+
"parameters": {
|
|
1300
|
+
"bw_filer_id": { "type": "string", "required": true, "description": "Funds_DAG canonical 13F filer id (BW-FILER-CIK{cik})." }
|
|
1301
|
+
},
|
|
1302
|
+
"pricing": { "model": "per_request", "cost_usd": 0.005, "currency": "USD", "billing_code": "filer_metrics_v1" },
|
|
1303
|
+
"tags": ["13f", "filer", "metrics", "funds"]
|
|
1304
|
+
},
|
|
1305
|
+
{
|
|
1306
|
+
"id": "filer-holdings",
|
|
1307
|
+
"name": "13F Filer Holdings",
|
|
1308
|
+
"description": "Top-N current holdings of a 13F filer from its canonical PortfolioSurface zarr (Funds_DAG filer_holdings_zarr — source_kind=filer_13f, teo_frequency=quarterly; SEC 13F-HR/HR-A snapshots back to ~2005). bw_sym_id-keyed post-D.8.1 migration; reports the in-ERM3 sleeve (coverage_in_erm3 fraction surfaced separately). Matches the schema of /api/data/funds/{bw_fund_id}/holdings and /api/data/etf/{ticker}/holdings. MASTER_BACKLOG D.8.8.",
|
|
1309
|
+
"endpoint": "/api/13f/filers/{bw_filer_id}/holdings",
|
|
1310
|
+
"method": "GET",
|
|
1311
|
+
"parameters": {
|
|
1312
|
+
"bw_filer_id": { "type": "string", "required": true, "description": "Funds_DAG canonical 13F filer id (BW-FILER-CIK{cik})." },
|
|
1313
|
+
"top": { "type": "integer", "required": false, "default": 25, "description": "Number of top holdings to return (1-1000)." }
|
|
1314
|
+
},
|
|
1315
|
+
"pricing": { "model": "per_request", "cost_usd": 0.005, "currency": "USD", "billing_code": "filer_holdings_v1" },
|
|
1316
|
+
"tags": ["13f", "filer", "holdings", "portfolio-surface", "funds"]
|
|
1317
|
+
},
|
|
1318
|
+
{
|
|
1319
|
+
"id": "filer-portfolio-history",
|
|
1320
|
+
"name": "13F Filer Portfolio History",
|
|
1321
|
+
"description": "A 13F filer's L1/L2/L3 portfolio return-decomposition time series (Funds_DAG filer_portfolios_zarr — ds_portfolio.zarr per-filer, quarterly). Same schema as /api/data/funds/{bw_fund_id}/portfolio and /api/data/etf/{ticker}/portfolio: portfolio_{gross,market,sector,subsector,idiosyncratic}_return + identity_residual, total_aum_usd, n_holdings_active, effective_n, top10_weight_sum, coverage_in_erm3, aum_in_erm3, portfolio_9box_distribution, dominant_9box. Constant-holdings-within-quarter weighting (industry-standard 13F-perf convention, D.8.22). MASTER_BACKLOG D.8.8.",
|
|
1322
|
+
"endpoint": "/api/13f/filers/{bw_filer_id}/portfolio",
|
|
1323
|
+
"method": "GET",
|
|
1324
|
+
"parameters": {
|
|
1325
|
+
"bw_filer_id": { "type": "string", "required": true, "description": "Funds_DAG canonical 13F filer id (BW-FILER-CIK{cik})." },
|
|
1326
|
+
"start_date": { "type": "string", "required": false, "description": "YYYY-MM-DD lower bound on report_date." },
|
|
1327
|
+
"end_date": { "type": "string", "required": false, "description": "YYYY-MM-DD upper bound on report_date." }
|
|
1328
|
+
},
|
|
1329
|
+
"pricing": { "model": "per_request", "cost_usd": 0.005, "currency": "USD", "billing_code": "filer_portfolio_history_v1" },
|
|
1330
|
+
"tags": ["13f", "filer", "return-attribution", "portfolio-surface", "funds"]
|
|
1331
|
+
},
|
|
1332
|
+
{
|
|
1333
|
+
"id": "filer-concentration",
|
|
1334
|
+
"name": "13F Filer Concentration Summary",
|
|
1335
|
+
"description": "Quarter-end concentration panel from per-filer ds_portfolio.zarr (median + latest effective N, top-5 / top-10 weight share, weight HHI). Optional ?start_date / ?end_date window.",
|
|
1336
|
+
"endpoint": "/api/13f/filers/{bw_filer_id}/concentration",
|
|
1337
|
+
"method": "GET",
|
|
1338
|
+
"parameters": {
|
|
1339
|
+
"bw_filer_id": { "type": "string", "required": true, "description": "Funds_DAG canonical 13F filer id (BW-FILER-CIK{cik})." },
|
|
1340
|
+
"start_date": { "type": "string", "required": false, "description": "YYYY-MM-DD lower bound on report_date." },
|
|
1341
|
+
"end_date": { "type": "string", "required": false, "description": "YYYY-MM-DD upper bound on report_date." }
|
|
1342
|
+
},
|
|
1343
|
+
"pricing": { "model": "per_request", "cost_usd": 0.005, "currency": "USD", "billing_code": "filer_concentration_v1" },
|
|
1344
|
+
"tags": ["13f", "filer", "concentration", "portfolio-surface"]
|
|
1345
|
+
},
|
|
1346
|
+
{
|
|
1347
|
+
"id": "filer-snapshot-json",
|
|
1348
|
+
"name": "13F Filer Snapshot (JSON)",
|
|
1349
|
+
"description": "Composed JSON snapshot for a single 13F filer. Bundles registry + latest metrics + top-25 holdings + portfolio history + cohort context. Cohort axis = filer_type × aum_tier (vs equity_style_9box on the fund side). No NAV section (filers have no NAV by construction); hedge section gated on D.8.10 Phase 3. Matching server-rendered PDF is /api/13f/filers/{bw_filer_id}/snapshot.pdf. MASTER_BACKLOG D.8.8 / D.8.9.",
|
|
1350
|
+
"endpoint": "/api/13f/filers/{bw_filer_id}/snapshot",
|
|
1351
|
+
"method": "GET",
|
|
1352
|
+
"parameters": {
|
|
1353
|
+
"bw_filer_id": { "type": "string", "required": true, "description": "Funds_DAG canonical 13F filer id (BW-FILER-CIK{cik})." }
|
|
1354
|
+
},
|
|
1355
|
+
"pricing": { "model": "per_request", "cost_usd": 0.01, "currency": "USD", "billing_code": "filer_snapshot_json_v1" },
|
|
1356
|
+
"tags": ["13f", "filer", "snapshot", "tearsheet"]
|
|
1357
|
+
},
|
|
1358
|
+
{
|
|
1359
|
+
"id": "filer-snapshot-pdf",
|
|
1360
|
+
"name": "13F Filer Snapshot (PDF)",
|
|
1361
|
+
"description": "Server-rendered F1 filer tearsheet PDF — same composition as /api/13f/filers/{bw_filer_id}/snapshot (JSON), rendered via Playwright (parity with fund F1). Letter landscape, single page. Cached 24h per (user, bw_filer_id, report_date). MASTER_BACKLOG D.8.8 / D.8.34.",
|
|
1362
|
+
"endpoint": "/api/13f/filers/{bw_filer_id}/snapshot.pdf",
|
|
1363
|
+
"method": "GET",
|
|
1364
|
+
"parameters": {
|
|
1365
|
+
"bw_filer_id": { "type": "string", "required": true, "description": "Funds_DAG canonical 13F filer id (BW-FILER-CIK{cik})." }
|
|
1366
|
+
},
|
|
1367
|
+
"pricing": { "model": "per_request", "cost_usd": 0.25, "currency": "USD", "billing_code": "filer_snapshot_pdf_v1" },
|
|
1368
|
+
"tags": ["13f", "filer", "snapshot", "pdf", "tearsheet"]
|
|
1369
|
+
},
|
|
1370
|
+
{
|
|
1371
|
+
"id": "filer-search",
|
|
1372
|
+
"name": "13F Filer Search",
|
|
1373
|
+
"description": "Free discovery endpoint for 13F filers. Returns bw_filer_id + filer_name + cik + filer_type + aum_tier + n_funds_managed for matching filers. Free (skipBilling) for rm_agent_live_* keys — paid follow-up calls via /api/13f/filers/{bw_filer_id}. Mirrors the /api/data/funds/search pattern.",
|
|
1374
|
+
"endpoint": "/api/13f/filers/search",
|
|
1375
|
+
"method": "GET",
|
|
1376
|
+
"parameters": {
|
|
1377
|
+
"q": { "type": "string", "required": true, "description": "Search query (filer name, partial match)." },
|
|
1378
|
+
"limit": { "type": "integer", "required": false, "default": 25, "description": "Max results (1-100)." }
|
|
1379
|
+
},
|
|
1380
|
+
"pricing": { "model": "per_request", "cost_usd": 0.0, "currency": "USD", "billing_code": "filer_search_v1" },
|
|
1381
|
+
"tags": ["13f", "filer", "search", "discovery"]
|
|
1382
|
+
},
|
|
1383
|
+
{
|
|
1384
|
+
"id": "etf-metrics",
|
|
1385
|
+
"name": "ETF Base Metrics (canonical PortfolioSurface)",
|
|
1386
|
+
"description": "Latest knowledge-mode metrics for a single ETF — registry-level metadata (portfolio_id, ticker, source_kind, teo_frequency, sponsor) + the latest aggregate metrics from the canonical PortfolioSurface zarr (aum_reported, aum_erm3, coverage_pct, n_total_holdings, report_date, availability_date). Symmetric to /api/data/funds/{bw_fund_id} and /api/13f/filers/{bw_filer_id} — closes the 'base entity metrics' parity gap for the ETF surface. MASTER_BACKLOG L.6 / D.9.",
|
|
1387
|
+
"endpoint": "/api/data/etf/{ticker}",
|
|
1388
|
+
"method": "GET",
|
|
1389
|
+
"parameters": {
|
|
1390
|
+
"ticker": { "type": "string", "required": true, "description": "ETF ticker, e.g. IVV." }
|
|
1391
|
+
},
|
|
1392
|
+
"pricing": { "model": "per_request", "cost_usd": 0.001, "currency": "USD", "billing_code": "etf_metrics_v1" },
|
|
1393
|
+
"performance": {
|
|
1394
|
+
"avg_latency_ms": 100,
|
|
1395
|
+
"p95_latency_ms": 200,
|
|
1396
|
+
"availability_sla": 99.5,
|
|
1397
|
+
"rate_limit_per_minute": 120
|
|
1398
|
+
},
|
|
1399
|
+
"confidence": {
|
|
1400
|
+
"data_quality_score": 0.98,
|
|
1401
|
+
"update_frequency": "daily",
|
|
1402
|
+
"sources": ["ishares_holdings", "erm3_secmaster"]
|
|
1403
|
+
},
|
|
1404
|
+
"tags": ["etf", "metrics", "portfolio-surface", "funds"]
|
|
1405
|
+
},
|
|
1406
|
+
{
|
|
1407
|
+
"id": "etf-search",
|
|
1408
|
+
"name": "ETF Search & Discovery",
|
|
1409
|
+
"description": "Free discovery endpoint for ETFs in the canonical universe. Substring + prefix search over ticker / name / sponsor in the committed cross-repo catalog (mirror of Funds_DAG configs/etf_universe.yaml). Returns ticker + bw_etf_id + name + sponsor + product_url per hit, with a ranking score (100 exact ticker; 70 ticker prefix; 50 ticker substring; 40 name word-prefix; 30 name substring; 20 sponsor). Empty q returns the universe (capped at limit). Mirrors the /api/data/funds/search + /api/13f/filers/search pattern. MASTER_BACKLOG L.6 / D.9.",
|
|
1410
|
+
"endpoint": "/api/data/etf/search",
|
|
1411
|
+
"method": "GET",
|
|
1412
|
+
"parameters": {
|
|
1413
|
+
"q": { "type": "string", "required": false, "description": "Search query (ticker / name / sponsor; case-insensitive)." },
|
|
1414
|
+
"limit": { "type": "integer", "required": false, "default": 25, "description": "Max rows returned (1-100)." }
|
|
1415
|
+
},
|
|
1416
|
+
"pricing": { "model": "per_request", "cost_usd": 0.0, "currency": "USD", "billing_code": "etf_search_v1" },
|
|
1417
|
+
"performance": {
|
|
1418
|
+
"avg_latency_ms": 20,
|
|
1419
|
+
"p95_latency_ms": 50,
|
|
1420
|
+
"availability_sla": 99.9,
|
|
1421
|
+
"rate_limit_per_minute": 120
|
|
1422
|
+
},
|
|
1423
|
+
"confidence": {
|
|
1424
|
+
"data_quality_score": 0.98,
|
|
1425
|
+
"update_frequency": "weekly",
|
|
1426
|
+
"sources": ["funds_dag.configs.etf_universe", "etf_master.json"]
|
|
1427
|
+
},
|
|
1428
|
+
"tags": ["etf", "search", "discovery", "free", "funds"]
|
|
1429
|
+
},
|
|
1430
|
+
{
|
|
1431
|
+
"id": "etf-holdings",
|
|
1432
|
+
"name": "ETF Holdings (canonical PortfolioSurface)",
|
|
1433
|
+
"description": "Top-N current holdings of an ETF from its canonical PortfolioSurface zarr (Funds_DAG etf_holdings_zarr — source_kind=etf, teo_frequency=daily; iShares today, State Street/Vanguard follow). In-ERM3 sleeve only — every holding carries a bw_sym_id. Surfaces report_date (sponsor 'Fund Holdings as of') and availability_date (when observed) distinctly. MASTER_BACKLOG L.6 / D.9.",
|
|
1434
|
+
"endpoint": "/api/data/etf/{ticker}/holdings",
|
|
1435
|
+
"method": "GET",
|
|
1436
|
+
"parameters": {
|
|
1437
|
+
"ticker": { "type": "string", "required": true, "description": "ETF ticker, e.g. IVV." },
|
|
1438
|
+
"top": { "type": "integer", "required": false, "default": 25, "description": "Number of top holdings to return (1-1000)." }
|
|
1439
|
+
},
|
|
1440
|
+
"pricing": { "model": "per_request", "cost_usd": 0.001, "currency": "USD", "billing_code": "etf_holdings_v1" },
|
|
1441
|
+
"performance": {
|
|
1442
|
+
"avg_latency_ms": 120,
|
|
1443
|
+
"p95_latency_ms": 250,
|
|
1444
|
+
"availability_sla": 99.5,
|
|
1445
|
+
"rate_limit_per_minute": 120
|
|
1446
|
+
},
|
|
1447
|
+
"confidence": {
|
|
1448
|
+
"data_quality_score": 0.98,
|
|
1449
|
+
"update_frequency": "daily",
|
|
1450
|
+
"sources": ["ishares_holdings", "erm3_secmaster"]
|
|
1451
|
+
},
|
|
1452
|
+
"tags": ["etf", "holdings", "portfolio-surface", "funds"]
|
|
1453
|
+
},
|
|
1454
|
+
{
|
|
1455
|
+
"id": "benchmark-context",
|
|
1456
|
+
"name": "Benchmark Surface + Context",
|
|
1457
|
+
"description": "A benchmark's canonical PortfolioSurface snapshot (Funds_DAG benchmark_surfaces_zarr, source_kind=benchmark): the BenchmarkContext (immutable definition — methodology, rebalance schedule, observation semantics, benchmark_kind, proxy/components) + the latest constituent weight vector (top-N). `id` accepts a bw_bench_id (BW-BENCH-SPY) or an alias (SPY, 70/30). v1: SPY (index_proxy via IVV holdings), EQ70-30 (blend 70% IWB + 30% IWM). MASTER_BACKLOG L.8.",
|
|
1458
|
+
"endpoint": "/api/data/benchmark/{id}",
|
|
1459
|
+
"method": "GET",
|
|
1460
|
+
"parameters": {
|
|
1461
|
+
"id": { "type": "string", "required": true, "description": "bw_bench_id (BW-BENCH-...) or alias (e.g. SPY, 70/30)." },
|
|
1462
|
+
"top": { "type": "integer", "required": false, "default": 25, "description": "Top constituents to return (1-1000)." }
|
|
1463
|
+
},
|
|
1464
|
+
"pricing": { "model": "per_request", "cost_usd": 0.001, "currency": "USD", "billing_code": "benchmark_context_v1" },
|
|
1465
|
+
"performance": { "avg_latency_ms": 120, "p95_latency_ms": 250, "availability_sla": 99.5, "rate_limit_per_minute": 120 },
|
|
1466
|
+
"confidence": { "data_quality_score": 0.97, "update_frequency": "daily", "sources": ["benchmark_surfaces_zarr", "ishares_holdings"] },
|
|
1467
|
+
"tags": ["benchmark", "portfolio-surface", "funds"]
|
|
1468
|
+
},
|
|
1469
|
+
{
|
|
1470
|
+
"id": "benchmark-fit",
|
|
1471
|
+
"name": "Benchmark Fit",
|
|
1472
|
+
"description": "BenchmarkFit (comparison facet): fit a subject portfolio's weight vector against a benchmark surface at a common teo (subject's latest teo ≤ as_of; benchmark then at its latest teo ≤ that — never peeking ahead). Returns active share, an active-weight RMS (coarse tracking-error proxy — factor-based TE is a follow-on), overlap, weight_in_benchmark / benchmark_coverage, and the top over/underweights. subject = a BW-* portfolio id (fund / 13F filer / ETF / benchmark) or an ETF ticker; benchmark = bw_bench_id or alias. MASTER_BACKLOG L.8.",
|
|
1473
|
+
"endpoint": "/api/data/benchmark-fit",
|
|
1474
|
+
"method": "GET",
|
|
1475
|
+
"parameters": {
|
|
1476
|
+
"subject": { "type": "string", "required": true, "description": "BW-* portfolio id (BW-FUND-/BW-FILER-/BW-ETF-/BW-BENCH-) or an ETF ticker." },
|
|
1477
|
+
"benchmark": { "type": "string", "required": true, "description": "bw_bench_id (BW-BENCH-...) or alias (e.g. SPY, 70/30)." },
|
|
1478
|
+
"as_of": { "type": "string", "required": false, "description": "YYYY-MM-DD upper bound on the subject's teo." },
|
|
1479
|
+
"top": { "type": "integer", "required": false, "default": 10, "description": "Top over/underweights to return (1-100)." }
|
|
1480
|
+
},
|
|
1481
|
+
"pricing": { "model": "per_request", "cost_usd": 0.002, "currency": "USD", "billing_code": "benchmark_fit_v1" },
|
|
1482
|
+
"performance": { "avg_latency_ms": 200, "p95_latency_ms": 400, "availability_sla": 99.5, "rate_limit_per_minute": 120 },
|
|
1483
|
+
"confidence": { "data_quality_score": 0.95, "update_frequency": "daily", "sources": ["benchmark_surfaces_zarr", "fund/filer/etf ds_ph.zarr"] },
|
|
1484
|
+
"tags": ["benchmark", "benchmark-fit", "active-share", "portfolio-surface"]
|
|
1485
|
+
},
|
|
1486
|
+
{
|
|
1487
|
+
"id": "etf-portfolio",
|
|
1488
|
+
"name": "ETF Return Decomposition",
|
|
1489
|
+
"description": "An ETF's L1/L2/L3 portfolio return-decomposition time series (Funds_DAG surface_portfolios_zarr) — same schema as the per-fund /api/funds/{bw_fund_id}/portfolio: portfolio_{gross,market,sector,subsector,idiosyncratic}_return + identity_residual, weight_sum, n_holdings_active, effective_n, top10_weight_sum. Reports weight_basis (v1: latest_holdings_constant — the factor profile of the ETF's current composition over ERM3 monthly's full history) and variance_shares (diversification-credited full-window market/sector/subsector/residual). MASTER_BACKLOG L.6.",
|
|
1490
|
+
"endpoint": "/api/data/etf/{ticker}/portfolio",
|
|
1491
|
+
"method": "GET",
|
|
1492
|
+
"parameters": {
|
|
1493
|
+
"ticker": { "type": "string", "required": true, "description": "ETF ticker, e.g. IWM." },
|
|
1494
|
+
"start_date": { "type": "string", "required": false, "description": "YYYY-MM-DD lower bound." },
|
|
1495
|
+
"end_date": { "type": "string", "required": false, "description": "YYYY-MM-DD upper bound." }
|
|
1496
|
+
},
|
|
1497
|
+
"pricing": { "model": "per_request", "cost_usd": 0.002, "currency": "USD", "billing_code": "etf_portfolio_v1" },
|
|
1498
|
+
"performance": { "avg_latency_ms": 150, "p95_latency_ms": 300, "availability_sla": 99.5, "rate_limit_per_minute": 120 },
|
|
1499
|
+
"confidence": { "data_quality_score": 0.95, "update_frequency": "daily", "sources": ["surface_portfolios_zarr", "erm3_monthly"] },
|
|
1500
|
+
"tags": ["etf", "return-attribution", "portfolio-surface", "funds"]
|
|
1501
|
+
},
|
|
1502
|
+
{
|
|
1503
|
+
"id": "benchmark-portfolio",
|
|
1504
|
+
"name": "Benchmark Return Decomposition",
|
|
1505
|
+
"description": "A benchmark's L1/L2/L3 portfolio return-decomposition time series (Funds_DAG surface_portfolios_zarr) — same schema as /api/data/etf/{ticker}/portfolio and /api/funds/{bw_fund_id}/portfolio. `id` accepts a bw_bench_id (BW-BENCH-SPY) or an alias (SPY, 70/30). Reports weight_basis (v1: latest_holdings_constant — the factor profile of the benchmark's current composition over ERM3 monthly's full history; the right view for a benchmark's risk profile) and variance_shares. MASTER_BACKLOG L.8.",
|
|
1506
|
+
"endpoint": "/api/data/benchmark/{id}/portfolio",
|
|
1507
|
+
"method": "GET",
|
|
1508
|
+
"parameters": {
|
|
1509
|
+
"id": { "type": "string", "required": true, "description": "bw_bench_id (BW-BENCH-...) or alias (e.g. SPY, 70/30)." },
|
|
1510
|
+
"start_date": { "type": "string", "required": false, "description": "YYYY-MM-DD lower bound." },
|
|
1511
|
+
"end_date": { "type": "string", "required": false, "description": "YYYY-MM-DD upper bound." }
|
|
1512
|
+
},
|
|
1513
|
+
"pricing": { "model": "per_request", "cost_usd": 0.002, "currency": "USD", "billing_code": "benchmark_portfolio_v1" },
|
|
1514
|
+
"performance": { "avg_latency_ms": 150, "p95_latency_ms": 300, "availability_sla": 99.5, "rate_limit_per_minute": 120 },
|
|
1515
|
+
"confidence": { "data_quality_score": 0.95, "update_frequency": "daily", "sources": ["surface_portfolios_zarr", "erm3_monthly"] },
|
|
1516
|
+
"tags": ["benchmark", "return-attribution", "portfolio-surface"]
|
|
1517
|
+
},
|
|
1518
|
+
{
|
|
1519
|
+
"id": "portfolio-evolution",
|
|
1520
|
+
"name": "Portfolio Evolution — what changed since last look",
|
|
1521
|
+
"description": "The Analyst M4 kernel. Given a portfolio_history (list of CmlPortfolioSnapshot — {as_of_date, holdings[]} pairs across time), returns a constant-holdings-within-segment return attribution + variance-share evolution + per-position trade-effect attribution. Two analytical paths: (a) actual vs static-w0 counterfactual return attribution (Brinson-style; isolates rebalancing P&L); (b) variance-share change attribution (compares variance composition at d_N vs d_0). Each slice carries an above_noise flag (k_R=1.5·sigma_residual·sqrt(N_months) for returns; k_V=2.0·sqrt(2/N) for variance shares). Reads M3c jsonb portfolio_history + ERM3 monthly; produces design-doc §5 response shape. v1 treats out-of-coverage holdings (ETFs, cash, bonds) as outside the modeled sleeve; M4.5 adds ETF look-through.",
|
|
1522
|
+
"endpoint": "/api/portfolio-evolution",
|
|
1523
|
+
"method": "POST",
|
|
1524
|
+
"parameters": {
|
|
1525
|
+
"portfolio_id": {
|
|
1526
|
+
"type": "string",
|
|
1527
|
+
"required": true,
|
|
1528
|
+
"description": "Stable identifier for the portfolio. Convention: 'cml/{cml_id}' for client portfolios, '13f/{cik}' for filer portfolios."
|
|
1529
|
+
},
|
|
1530
|
+
"portfolio_history": {
|
|
1531
|
+
"type": "array",
|
|
1532
|
+
"required": true,
|
|
1533
|
+
"description": "M3c CmlPortfolioSnapshot[] jsonb shape — list of {as_of_date, holdings[{ticker, weight}], ingest_adapter} dated points oldest→newest.",
|
|
1534
|
+
"items": {
|
|
1535
|
+
"type": "object",
|
|
1536
|
+
"properties": {
|
|
1537
|
+
"as_of_date": { "type": "string", "required": true, "description": "ISO YYYY-MM-DD" },
|
|
1538
|
+
"holdings": { "type": "array", "required": true, "description": "[{ticker, weight}] — weights renormalized to 1.0 on the ERM3-covered sleeve" }
|
|
1539
|
+
}
|
|
1540
|
+
}
|
|
1541
|
+
},
|
|
1542
|
+
"include_full_breakdown": {
|
|
1543
|
+
"type": "boolean",
|
|
1544
|
+
"required": false,
|
|
1545
|
+
"description": "If true, includes _monthly_breakdown — per-month L3 components and holding-quarter mapping. Default false (cheaper).",
|
|
1546
|
+
"default": false
|
|
1547
|
+
}
|
|
1548
|
+
},
|
|
1549
|
+
"pricing": {
|
|
1550
|
+
"model": "per_request",
|
|
1551
|
+
"cost_usd": 0.04,
|
|
1552
|
+
"currency": "USD",
|
|
1553
|
+
"min_charge": 0.03,
|
|
1554
|
+
"billing_code": "portfolio_evolution_m4_v1"
|
|
1555
|
+
},
|
|
1556
|
+
"performance": {
|
|
1557
|
+
"avg_latency_ms": 250,
|
|
1558
|
+
"p95_latency_ms": 500,
|
|
1559
|
+
"availability_sla": 99.5,
|
|
1560
|
+
"rate_limit_per_minute": 60
|
|
1561
|
+
},
|
|
1562
|
+
"confidence": {
|
|
1563
|
+
"data_quality_score": 0.96,
|
|
1564
|
+
"update_frequency": "monthly",
|
|
1565
|
+
"sources": ["erm3_monthly", "cml_activation_state.portfolio_history"],
|
|
1566
|
+
"methodology_url": "https://riskmodels.app/docs/m4-portfolio-evolution"
|
|
1567
|
+
},
|
|
1568
|
+
"tags": ["the-analyst", "portfolio-evolution", "return-attribution", "what-changed", "m4"],
|
|
1569
|
+
"examples": [
|
|
1570
|
+
{
|
|
1571
|
+
"request": {
|
|
1572
|
+
"portfolio_id": "cml/abc123",
|
|
1573
|
+
"portfolio_history": [
|
|
1574
|
+
{ "as_of_date": "2026-01-31", "holdings": [{ "ticker": "AAPL", "weight": 0.5 }, { "ticker": "NVDA", "weight": 0.5 }] },
|
|
1575
|
+
{ "as_of_date": "2026-04-30", "holdings": [{ "ticker": "AAPL", "weight": 0.3 }, { "ticker": "NVDA", "weight": 0.4 }, { "ticker": "META", "weight": 0.3 }] }
|
|
1576
|
+
]
|
|
1577
|
+
},
|
|
1578
|
+
"response": {
|
|
1579
|
+
"portfolio_id": "cml/abc123",
|
|
1580
|
+
"window": { "from_date": "2026-01-31", "to_date": "2026-04-30", "n_dated_points": 2 },
|
|
1581
|
+
"return_attribution": {
|
|
1582
|
+
"total_return_pct": 4.2,
|
|
1583
|
+
"static_return_pct": 3.8,
|
|
1584
|
+
"trade_effect_bps": 40,
|
|
1585
|
+
"noise_floor_bps": 220,
|
|
1586
|
+
"above_noise": false
|
|
1587
|
+
}
|
|
1588
|
+
}
|
|
1589
|
+
}
|
|
1590
|
+
]
|
|
1591
|
+
},
|
|
1592
|
+
{
|
|
1593
|
+
"id": "artifact-render",
|
|
1594
|
+
"name": "Artifact registry render",
|
|
1595
|
+
"description": "Deterministic render-once artifact from the intelligence registry (fund / filer / client_portfolio subjects). Invokes render-svc POST /artifacts/render. Returns JSON chart/table/narrative payloads or PNG/SVG bytes (base64). Chat tool: render_artifact; MCP: riskmodels_render_artifact.",
|
|
1596
|
+
"endpoint": "/artifacts/render",
|
|
1597
|
+
"method": "POST",
|
|
1598
|
+
"parameters": {
|
|
1599
|
+
"slug": {
|
|
1600
|
+
"type": "string",
|
|
1601
|
+
"required": true,
|
|
1602
|
+
"description": "Artifact slug (e.g. top_holdings_erm_stacked, narrative_profile)"
|
|
1603
|
+
},
|
|
1604
|
+
"version": {
|
|
1605
|
+
"type": "string",
|
|
1606
|
+
"required": false,
|
|
1607
|
+
"description": "Semantic version tag, default v1",
|
|
1608
|
+
"default": "v1"
|
|
1609
|
+
},
|
|
1610
|
+
"subject_id": {
|
|
1611
|
+
"type": "string",
|
|
1612
|
+
"required": true,
|
|
1613
|
+
"description": "BW-FUND-…, BW-FILER-…, or BW-PORTFOLIO-…"
|
|
1614
|
+
},
|
|
1615
|
+
"as_of": {
|
|
1616
|
+
"type": "string",
|
|
1617
|
+
"required": false,
|
|
1618
|
+
"description": "YYYY-MM-DD or latest",
|
|
1619
|
+
"default": "latest"
|
|
1620
|
+
},
|
|
1621
|
+
"format": {
|
|
1622
|
+
"type": "string",
|
|
1623
|
+
"required": false,
|
|
1624
|
+
"description": "json | png | svg",
|
|
1625
|
+
"enum": ["json", "png", "svg"],
|
|
1626
|
+
"default": "json"
|
|
1627
|
+
}
|
|
1628
|
+
},
|
|
1629
|
+
"pricing": {
|
|
1630
|
+
"model": "per_request",
|
|
1631
|
+
"tier": "premium",
|
|
1632
|
+
"cost_usd": 0.05,
|
|
1633
|
+
"currency": "USD",
|
|
1634
|
+
"billing_code": "artifact_render_v1"
|
|
1635
|
+
},
|
|
1636
|
+
"performance": {
|
|
1637
|
+
"avg_latency_ms": 1200,
|
|
1638
|
+
"p95_latency_ms": 4000,
|
|
1639
|
+
"availability_sla": 99.5,
|
|
1640
|
+
"rate_limit_per_minute": 30
|
|
1641
|
+
},
|
|
1642
|
+
"confidence": {
|
|
1643
|
+
"data_quality_score": 0.98,
|
|
1644
|
+
"update_frequency": "daily",
|
|
1645
|
+
"sources": ["Funds_DAG", "ERM3", "render-svc"]
|
|
1646
|
+
},
|
|
1647
|
+
"tags": ["artifact", "registry", "render", "fund", "filer"]
|
|
923
1648
|
}
|
|
924
1649
|
]
|