Automation
riskofficer
Manage investment portfolios, calculate risk metrics
---
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)
automation
By
Comments
Sign in to leave a comment