ワンクリックで
trader-portfolio-cg
Mean-variance portfolio optimization via Conjugate Gradient — 40-60× faster than the legacy Neumann path (ADR-126 Phase 3, ADR-123 Wedge 8)
メニュー
Mean-variance portfolio optimization via Conjugate Gradient — 40-60× faster than the legacy Neumann path (ADR-126 Phase 3, ADR-123 Wedge 8)
SOC 職業分類に基づく
One-command drift detection. Composes audit-list + oia-audit + audit-trend into a single primitive — finds the most recent audit in `metaharness-audit` namespace, runs a fresh audit against the current repo, diffs them via ADR-152 §3.1 similarity, and alerts when structural distance crosses `--threshold`. Iter 53 of ADR-150 deep integration.
ADR-152 — weighted similarity between two harness fingerprints (genome + score JSON). Returns overall score in [0,1] plus per-component breakdown (cosine over 9 numerics, categorical agreement over 4 enums, jaccard over agent_topology). Unblocks ADR-151 §3.2 Recommender, §3.3 Drift Detection, §3.5 Plugin Compat. Pure-TS, no `@metaharness/*` dep — preserves ADR-150's four architectural constraints.
Composite Phase-2 audit worker (ADR-150). Bundles harness oia-manifest + threat-model + mcp-scan into one timestamped audit record stored in the `metaharness-audit` memory namespace. Designed for cron-scheduled drift detection.
7-section repo readiness report from `metaharness genome <path>`. Returns repo_type / agent_topology / risk_score / mcp_surface / test_confidence / publish_readiness. Pure-read; degrades gracefully (ADR-150).
Static security scan of a harness's declared MCP surface via `harness mcp-scan <path>`. Reads `.mcp/servers.json` + `.harness/claims.json`. Pure-read, no dispatch. Exits 1 on findings at or above `--fail-on` severity.
Scaffold a custom AI agent harness via `metaharness new <name> --template <id> --host <id>`. Defaults to DRY-RUN (no writes) unless --confirm is passed. Refuses to write to the calling repo root or anywhere inside it. Honors ADR-150 architectural constraint + ruflo's "destructive-action confirmation" pattern.
| name | trader-portfolio-cg |
| description | Mean-variance portfolio optimization via Conjugate Gradient — 40-60× faster than the legacy Neumann path (ADR-126 Phase 3, ADR-123 Wedge 8) |
| allowed-tools | Bash Read mcp__ruflo-sublinear__solve mcp__claude-flow__memory_store mcp__claude-flow__memory_retrieve mcp__claude-flow__memory_search mcp__claude-flow__agentdb_pattern-search |
| argument-hint | [--portfolio-id ID] [--tolerance 1e-6] |
Solve the mean-variance optimization Σ · x = μ via Conjugate Gradient instead of the legacy Neumann series.
Why CG instead of Neumann (ADR-123 Wedge 8):
npx neural-trader --portfolio optimize)The covariance matrix Σ is symmetric positive-definite by construction (it's a Gram matrix on real returns), so CG is provably optimal — it converges in at most n iterations with no preconditioning, and typically far fewer when eigenvalues cluster.
Disable flag: set RUFLO_NEURAL_TRADER_DISABLE_CG=1 to skip the CG path entirely and fall through to step 4's legacy Neumann route. Useful for A/B validation or when an upstream covariance regression breaks SPD.
Native dispatch flag: set RUFLO_SUBLINEAR_NATIVE=1 to force the adapter to attempt the native mcp__ruflo-sublinear__solve path even when globalThis doesn't expose the tool (e.g. when the harness mounts it via a different transport). On any native-dispatch failure the adapter cleanly falls back to the local JS CG and records method: 'cg-local' in the artifact metadata — so the regression is auditable.
Steps:
Ensure neural-trader is available:
npm ls neural-trader 2>/dev/null || npm install --ignore-scripts neural-trader
Read the current covariance matrix Σ and expected-return vector μ from neural-trader's portfolio API:
# Primary path (preferred — clean JSON):
npx neural-trader --portfolio current --json
# Fallback paths if the --json flag is unavailable on the installed version:
npx neural-trader --portfolio current # parse the text output
# OR pull from AgentDB if a prior run stored the matrix there:
mcp__claude-flow__memory_search({ query: "covariance matrix current", namespace: "trading-risk", limit: 1 })
The skill expects the response to include covariance: number[][] (n × n) and expectedReturns: number[] (length n).
Solve Σ · x = μ via the SublinearAdapter (preferred path) when RUFLO_NEURAL_TRADER_DISABLE_CG is unset:
import { sublinearAdapter } from '../../src/sublinear-adapter.mjs';
const result = await sublinearAdapter.solveCG(COVARIANCE, EXPECTED_RETURNS, {
tolerance: 1e-6,
maxIterations: 200,
});
// result.solution — optimal weights (number[])
// result.iterations — CG iterations executed
// result.residual — final ||A·x − b||₂
// result.latencyMs — wall-clock latency
// result.method — 'cg-sublinear-native' | 'cg-local' <-- READ THIS
// result.solver — 'sublinear-time-solver@1.7.0' | 'local-js-cg'
// result.degraded — true if input failed SPD checks (fall back to step 4)
The adapter does the dispatch itself: it probes for mcp__ruflo-sublinear__solve on globalThis (and honours RUFLO_SUBLINEAR_NATIVE=1 as a manual override), routes through the native kernel when reachable, and falls back transparently to the embedded ~50-LOC JS CG when not. The math is identical either way — CG, dense form, n × n SPD covariance. The operator reads result.method to know which backend produced the artifact.
The native MCP tool's wire shape (for direct callers who want to bypass the adapter):
mcp__ruflo-sublinear__solve({
matrix: COVARIANCE,
rhs: EXPECTED_RETURNS,
algorithm: "cg",
tolerance: 1e-6,
maxIterations: 200
})
Output:
{ solution: number[], iterations: number, residual: number }
Fallback (legacy Neumann) — if step 3 reports degraded: true (non-SPD input, non-square matrix, MCP error) OR if RUFLO_NEURAL_TRADER_DISABLE_CG=1:
npx neural-trader --portfolio optimize
Capture the weights output and tag the artifact metadata with method: 'neumann-fallback' and a reason field.
Store the optimal weights to trading-risk namespace with full provenance metadata. Take method and solver straight from the adapter's result so the operator can verify which backend ran:
mcp__claude-flow__memory_store({
key: "portfolio-weights-PORTFOLIO_ID-TIMESTAMP",
namespace: "trading-risk",
value: JSON.stringify({
weights: result.solution, // number[] from step 3 (or weights from step 4 fallback)
method: result.method, // 'cg-sublinear-native' | 'cg-local' | 'neumann-fallback'
solver: result.solver, // 'sublinear-time-solver@1.7.0' | 'local-js-cg' | 'neural-trader-cli'
iterations: result.iterations,
residual: result.residual,
latencyMs: result.latencyMs,
capturedAt: NEW_DATE_ISO,
reason: FALLBACK_REASON || null
})
})
The trading-risk namespace is canonical (ADR-126 Phase 1; the five-namespace alignment). Long-lived — no TTL — because portfolio weights are the audit trail Phase 4 will Ed25519-sign.
Cross-check against historical patterns (optional but recommended):
mcp__claude-flow__agentdb_pattern-search({
query: "portfolio weights Sharpe regime:CURRENT_REGIME",
namespace: "trading-risk"
})
If the new weights differ by more than 30% in any single asset from the historical median, flag for human review before applying. This is a guard-rail, not a hard block.
Acceptance criteria (ADR-126 Phase 3):
||cg − neumann||_∞ < 1e-4 on a fixed seed.cg-sublinear-native, cg-local, and neumann-fallback.Refs:
plugins/ruflo-neural-trader/src/sublinear-adapter.ts (the adapter)plugins/ruflo-neural-trader/benchmarks/portfolio-cg.bench.ts (the measured numbers)