协作头脑风暴
brainstorming
在实现前澄清需求、探索设计选择,并形成清晰的开发方向。
riskofficer【开发与工程】Manage investment portfolios, calculate risk metrics (VaR, Monte Carlo, Stress Tests), and optimize allocations using Risk Parity or Calmar Ratio
独立 GitHub 快照 · 自动分类 · 以原作者文档为准
This skill connects to RiskOfficer API to manage investment portfolios and calculate risks.
RISK_OFFICER_TOKEN=ro_pat_...Or configure in ~/.openclaw/openclaw.json:
{
"skills": {
"entries": {
"riskofficer": {
"enabled": true,
"apiKey": "ro_pat_..."
}
}
}
}
https://api.riskofficer.tech/api/v1
All requests require header: Authorization: Bearer ${RISK_OFFICER_TOKEN}
When user asks to see their portfolios, list portfolios, or show portfolio overview:
curl -s "https://api.riskofficer.tech/api/v1/portfolios/list" \
-H "Authorization: Bearer ${RISK_OFFICER_TOKEN}"
Response contains array of portfolios with: id, name, total_value, currency, positions_count, broker, sandbox.
When user asks about a specific portfolio or wants to see positions:
curl -s "https://api.riskofficer.tech/api/v1/portfolio/snapshot/{snapshot_id}" \
-H "Authorization: Bearer ${RISK_OFFICER_TOKEN}"
Response contains: name, total_value, currency, positions (array with ticker, quantity, current_price, value, weight).
When user asks for total/combined portfolio, overall position, or "show everything together":
curl -s "https://api.riskofficer.tech/api/v1/portfolio/aggregated?type=all" \
-H "Authorization: Bearer ${RISK_OFFICER_TOKEN}"
Query params:
type=production — manual + broker (sandbox=false)type=sandbox — broker (sandbox=true) onlytype=all — everything (default)Response:
portfolio.positions — all positions merged across portfoliosportfolio.total_value — total value in base currencyportfolio.currency — base currency (RUB or USD)portfolio.sources_count — number of portfolios aggregatedExample response:
{
"portfolio": {
"positions": [
{"ticker": "SBER", "quantity": 150, "value": 42795, "sources": ["Т-Банк", "Manual"]},
{"ticker": "AAPL", "quantity": 10, "value": 189500, "original_currency": "USD"}
],
"total_value": 1500000,
"currency": "RUB",
"sources_count": 3
},
"snapshot_id": "uuid-of-aggregated"
}
Currency conversion: Positions in different currencies are automatically converted to base currency using current exchange rates (CBR for RUB).
When user wants to see aggregated portfolio in different currency:
curl -s -X PATCH "https://api.riskofficer.tech/api/v1/portfolio/{aggregated_snapshot_id}/settings" \
-H "Authorization: Bearer ${RISK_OFFICER_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"base_currency": "USD"}'
Supported currencies: RUB, USD
After changing, aggregated portfolio recalculates automatically.
User prompt examples:
When user wants to exclude a portfolio from total calculation:
curl -s -X PATCH "https://api.riskofficer.tech/api/v1/portfolio/{snapshot_id}/settings" \
-H "Authorization: Bearer ${RISK_OFFICER_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"include_in_aggregated": false}'
Use cases:
When user wants to create a new portfolio with specific positions:
curl -s -X POST "https://api.riskofficer.tech/api/v1/portfolio/manual" \
-H "Authorization: Bearer ${RISK_OFFICER_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"name": "Portfolio Name",
"positions": [
{"ticker": "SBER", "quantity": 100},
{"ticker": "GAZP", "quantity": 50}
]
}'
IMPORTANT RULE - Single Currency: All assets in a portfolio must be in the same currency.
When user wants to modify an existing portfolio:
curl -s "https://api.riskofficer.tech/api/v1/portfolio/snapshot/{snapshot_id}" \
-H "Authorization: Bearer ${RISK_OFFICER_TOKEN}"
curl -s -X POST "https://api.riskofficer.tech/api/v1/portfolio/manual" \
-H "Authorization: Bearer ${RISK_OFFICER_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"name": "<same name from step 1>",
"positions": [<updated list of all positions>]
}'
IMPORTANT: Always show user what will change and ask for confirmation before updating.
When user asks about connected brokers or broker status:
curl -s "https://api.riskofficer.tech/api/v1/brokers/connections" \
-H "Authorization: Bearer ${RISK_OFFICER_TOKEN}"
When user wants to sync/update portfolio from Tinkoff (broker must be connected via app):
curl -s -X POST "https://api.riskofficer.tech/api/v1/portfolio/proxy/broker/tinkoff/portfolio" \
-H "Authorization: Bearer ${RISK_OFFICER_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"sandbox": false}'
If response is 400 with missing_api_key, broker is not connected. Explain how to connect:
When user asks to calculate risks, VaR, or risk metrics:
curl -s -X POST "https://api.riskofficer.tech/api/v1/risk/calculate-var" \
-H "Authorization: Bearer ${RISK_OFFICER_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"portfolio_snapshot_id": "{snapshot_id}",
"method": "historical",
"confidence": 0.95,
"horizon_days": 1
}'
Methods: historical, parametric, garch
This returns calculation_id. Poll for result:
curl -s "https://api.riskofficer.tech/api/v1/risk/calculation/{calculation_id}" \
-H "Authorization: Bearer ${RISK_OFFICER_TOKEN}"
Wait until status is done, then present results.
When user asks for Monte Carlo simulation:
curl -s -X POST "https://api.riskofficer.tech/api/v1/risk/monte-carlo" \
-H "Authorization: Bearer ${RISK_OFFICER_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"portfolio_snapshot_id": "{snapshot_id}",
"simulations": 1000,
"horizon_days": 365,
"model": "gbm"
}'
Poll: GET /api/v1/risk/monte-carlo/{simulation_id}
When user asks for stress test:
First, get available crises:
curl -s "https://api.riskofficer.tech/api/v1/risk/stress-test/crises" \
-H "Authorization: Bearer ${RISK_OFFICER_TOKEN}"
Then run stress test:
curl -s -X POST "https://api.riskofficer.tech/api/v1/risk/stress-test" \
-H "Authorization: Bearer ${RISK_OFFICER_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"portfolio_snapshot_id": "{snapshot_id}",
"crisis": "covid_19"
}'
Poll: GET /api/v1/risk/stress-test/{stress_test_id}
When user asks to optimize portfolio or balance risks:
curl -s -X POST "https://api.riskofficer.tech/api/v1/portfolio/{snapshot_id}/optimize" \
-H "Authorization: Bearer ${RISK_OFFICER_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"optimization_mode": "preserve_directions",
"constraints": {
"max_weight": 0.30,
"min_weight": 0.02
}
}'
Modes:
long_only: All weights ≥ 0preserve_directions: Keep long/short as-isunconstrained: Any direction allowedPoll: GET /api/v1/portfolio/optimizations/{optimization_id}
Result: GET /api/v1/portfolio/optimizations/{optimization_id}/result
When user asks for Calmar optimization, maximize Calmar Ratio (CAGR / |Max Drawdown|). Requires 200+ trading days of price history per ticker (backend requests 252 days). If user has short history, suggest Risk Parity instead.
curl -s -X POST "https://api.riskofficer.tech/api/v1/portfolio/{snapshot_id}/optimize-calmar" \
-H "Authorization: Bearer ${RISK_OFFICER_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"optimization_mode": "long_only",
"constraints": {
"max_weight": 0.50,
"min_weight": 0.05,
"min_expected_return": 0.0,
"max_drawdown_limit": 0.15,
"min_calmar_target": 0.5
}
}'
Poll: GET /api/v1/portfolio/optimizations/{optimization_id} (check optimization_type === "calmar_ratio").
Result: GET /api/v1/portfolio/optimizations/{optimization_id}/result — includes current_metrics, optimized_metrics (cagr, max_drawdown, calmar_ratio, recovery_time_days).
Apply: same as Risk Parity — POST /api/v1/portfolio/optimizations/{optimization_id}/apply.
IMPORTANT: Always show rebalancing plan and ask for explicit user confirmation first!
curl -s -X POST "https://api.riskofficer.tech/api/v1/portfolio/optimizations/{optimization_id}/apply" \
-H "Authorization: Bearer ${RISK_OFFICER_TOKEN}"
Note: Quant subscription is currently FREE for all users. All features work without payment.
When you need to check if user has Quant subscription:
curl -s "https://api.riskofficer.tech/api/v1/subscription/status" \
-H "Authorization: Bearer ${RISK_OFFICER_TOKEN}"
Currently all users have has_subscription: true (free tier enabled).
VaR, Monte Carlo, Stress Test, and Optimization are asynchronous.
Polling pattern:
calculation_id / simulation_id / optimization_idstatus field:
pending or processing → keep pollingdone → present resultsfailed → show error messageTypical times:
| Operation | Typical Time |
|---|---|
| VaR | 3-10 seconds |
| Monte Carlo | 10-30 seconds |
| Stress Test | 5-15 seconds |
| Optimization | 10-30 seconds |
User communication:
Single Currency Rule (Manual/Broker portfolios): Each individual portfolio must have same-currency assets. Cannot mix SBER (RUB) with AAPL (USD) in one manual portfolio. Suggest separate portfolios.
Aggregated Portfolio: The aggregated portfolio CAN contain assets in different currencies - they are automatically converted to base currency (RUB or USD) using CBR rates.
Subscription: Monte Carlo, Stress Test, and Optimization are Quant features (currently free for all users). VaR is always FREE.
Broker Integration: User must connect broker in RiskOfficer app first. Cannot connect via chat (security).
Confirmations: Before applying optimizations or making significant portfolio changes, always show what will change and ask for confirmation.
Async Operations: VaR, Monte Carlo, Stress Test, and Optimization are async. Poll for results.
Error Handling:
User: "Show my portfolios" → Call GET /portfolios/list → Format nicely with values, positions count, last updated
User: "Покажи всё вместе" / "Total portfolio" / "Сколько у меня всего?" → Call GET /portfolio/aggregated?type=all → Show total value, all positions merged, sources count → Note which positions were converted from other currencies
User: "Покажи в долларах" / "Switch to USD" → Call PATCH /portfolio/{aggregated_id}/settings with {"base_currency": "USD"} → Call GET /portfolio/aggregated again → Show portfolio in new currency
User: "What are the risks of my main portfolio?" → Call GET /portfolios/list to find the portfolio → Call POST /risk/calculate-var → Poll until done → Present VaR, CVaR, volatility, risk contributions → Offer optimization if risks are unbalanced
User: "Оптимизируй портфель по Калмару" / "Optimize using Calmar Ratio" / "Maximize return per drawdown" → Call GET /portfolios/list or aggregated to get snapshot_id → Call POST /portfolio/{snapshot_id}/optimize-calmar with optimization_mode and optional constraints → If 400 INSUFFICIENT_HISTORY: explain need 200+ trading days of history, suggest Risk Parity as alternative → Poll GET /optimizations/{id} until status is done → Call GET /optimizations/{id}/result — show current_metrics vs optimized_metrics (Calmar ratio, CAGR, max drawdown) → Show rebalancing plan and ask for confirmation before apply
User: "Add Apple to my portfolio" → Check portfolio currency (RUB) vs AAPL currency (USD) → Explain cannot mix, suggest creating separate USD portfolio
User: "Run Monte Carlo" → Call POST /risk/monte-carlo with portfolio snapshot → Poll until done → Present simulation results with percentiles and projections