---
name: riskofficer
description: Manage investment portfolios, calculate risk metrics (VaR, Monte Carlo, Stress Tests), and optimize allocations using Risk Parity or Calmar Ratio
metadata: {"openclaw":{"requires":{"env":["RISK_OFFICER_TOKEN"]},"primaryEnv":"RISK_OFFICER_TOKEN","emoji":"📊","homepage":"https://riskofficer.tech"}}
---
## RiskOfficer Portfolio Management
This skill connects to RiskOfficer API to manage investment portfolios and calculate risks.
### Setup
1. Open RiskOfficer app → Settings → API Keys
2. Create new token for "OpenClaw"
3. Set environment variable: `RISK_OFFICER_TOKEN=ro_pat_...`
Or configure in `~/.openclaw/openclaw.json`:
```json
{
"skills": {
"entries": {
"riskofficer": {
"enabled": true,
"apiKey": "ro_pat_..."
}
}
}
}
```
### API Base URL
```
https://api.riskofficer.tech/api/v1
```
All requests require header: `Authorization: Bearer ${RISK_OFFICER_TOKEN}`
---
## Available Commands
### Portfolio Management
#### List Portfolios
When user asks to see their portfolios, list portfolios, or show portfolio overview:
```bash
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.
#### Get Portfolio Details
When user asks about a specific portfolio or wants to see positions:
```bash
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).
#### Get Aggregated Portfolio
When user asks for total/combined portfolio, overall position, or "show everything together":
```bash
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) only
- `type=all` — everything (default)
**Response:**
- `portfolio.positions` — all positions merged across portfolios
- `portfolio.total_value` — total value in base currency
- `portfolio.currency` — base currency (RUB or USD)
- `portfolio.sources_count` — number of portfolios aggregated
**Example response:**
```json
{
"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).
#### Change Base Currency (Aggregated Portfolio)
When user wants to see aggregated portfolio in different currency:
```bash
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:**
- "Покажи всё в долларах" → change base_currency to USD
- "Переведи портфель в рубли" → change base_currency to RUB
#### Include/Exclude from Aggregated
When user wants to exclude a portfolio from total calculation:
```bash
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:**
- "Не учитывай песочницу в общем портфеле" → exclude sandbox
- "Убери демо-портфель из расчёта" → exclude manual portfolio
#### Create Manual Portfolio
When user wants to create a new portfolio with specific positions:
```bash
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.
- RUB assets: SBER, GAZP, LKOH, YNDX, etc.
- USD assets: AAPL, MSFT, GOOGL, etc.
Cannot mix! If user tries to mix currencies, explain and suggest creating separate portfolios.
#### Update Portfolio (Add/Remove Positions)
When user wants to modify an existing portfolio:
1. First get current portfolio to find the name:
```bash
curl -s "https://api.riskofficer.tech/api/v1/portfolio/snapshot/{snapshot_id}" \
-H "Authorization: Bearer ${RISK_OFFICER_TOKEN}"
```
2. Then create new snapshot with updated positions (use same name):
```bash
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.
---
### Broker Integration
#### List Connected Brokers
When user asks about connected brokers or broker status:
```bash
curl -s "https://api.riskofficer.tech/api/v1/brokers/connections" \
-H "Authorization: Bearer ${RISK_OFFICER_TOKEN}"
```
#### Refresh Portfolio from Tinkoff
When user wants to sync/update portfolio from Tinkoff (broker must be connected via app):
```bash
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:
1. Get API token from https://www.tbank.ru/invest/settings/api/
2. Open RiskOfficer app → Settings → Brokers → Connect Tinkoff
3. Paste token and connect
---
### Risk Calculations
#### Calculate VaR (FREE)
When user asks to calculate risks, VaR, or risk metrics:
```bash
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:
```bash
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.
#### Run Monte Carlo (QUANT - currently free for all users)
When user asks for Monte Carlo simulation:
```bash
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}`
#### Run Stress Test (QUANT - currently free for all users)
When user asks for stress test:
First, get available crises:
```bash
curl -s "https://api.riskofficer.tech/api/v1/risk/stress-test/crises" \
-H "Authorization: Bearer ${RISK_OFFICER_TOKEN}"
```
Then run stress test:
```bash
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}`
---
### Portfolio Optimization (QUANT - currently free for all users)
#### Risk Parity Optimization
When user asks to optimize portfolio or balance risks:
```bash
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 ≥ 0
- `preserve_directions`: Keep long/short as-is
- `unconstrained`: Any direction allowed
Poll: `GET /api/v1/portfolio/optimizations/{optimization_id}`
Result: `GET /api/v1/portfolio/optimizations/{optimization_id}/result`
#### Calmar Ratio Optimization
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.
```bash
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`.
#### Apply Optimization
**IMPORTANT:** Always show rebalancing plan and ask for explicit user confirmation fi
... (truncated)Help answer questions about Catholicism accurately
Analyze budget vs actual
Push decisions to Arbiter Zebu for async human review.
Create, validate, and publish Agent Skills following