stock/examples/06_portfolio_risk.py
2026-02-27 03:17:12 +08:00

160 lines
4.8 KiB
Python

"""Portfolio Risk Management Example.
Demonstrates portfolio-level risk controls including
position limits, drawdown control, and VaR calculations.
"""
from openclaw.portfolio.risk import (
PortfolioRiskManager,
PositionConcentrationLimit,
DrawdownController,
PortfolioVaR,
)
from datetime import datetime
def main():
"""Run the portfolio risk example."""
print("=" * 60)
print("OpenClaw Trading - Portfolio Risk Management")
print("=" * 60)
# 1. Initialize risk manager
print("\n1. Initializing risk manager...")
manager = PortfolioRiskManager(
portfolio_id="demo_portfolio",
max_concentration_pct=0.20, # Max 20% per position
max_drawdown_pct=0.10, # Max 10% drawdown
)
print(f" Max Position: {manager.concentration_limit.max_concentration_pct:.0%}")
print(f" Max Drawdown: {manager.drawdown_monitor.max_drawdown_threshold:.0%}")
# 2. Position concentration check
print("\n2. Position Concentration Checks:")
print("-" * 60)
test_positions = [
("AAPL", 1500.0, 10000.0), # 15% - OK
("TSLA", 2500.0, 10000.0), # 25% - Too high
("GOOGL", 800.0, 10000.0), # 8% - OK
]
for symbol, position_value, portfolio_value in test_positions:
concentration = position_value / portfolio_value
result = manager.check_position_limit(
symbol=symbol,
position_value=position_value,
total_portfolio_value=portfolio_value
)
status = "✓ ALLOWED" if result.is_allowed else "✗ BLOCKED"
print(f"\n {symbol}: ${position_value:,.2f} ({concentration:.1%})")
print(f" Status: {status}")
if not result.is_allowed:
print(f" Reason: {result.message}")
# 3. Drawdown control
print("\n3. Drawdown Control:")
print("-" * 60)
controller = DrawdownController(max_drawdown_threshold=0.10)
# Simulate portfolio values
values = [
(10000.0, "Start"),
(10500.0, "Peak"),
(10200.0, "Small drop"),
(9500.0, "5% drawdown"),
(8800.0, "12% drawdown - ALERT!"),
]
peak = 10000.0
for value, label in values:
controller.update_portfolio_value(value)
drawdown = (peak - value) / peak if value < peak else 0
if value > peak:
peak = value
blocked = controller.is_drawdown_exceeded()
block_status = "BLOCKED" if blocked else "OK"
print(f" {label}: ${value:,.2f} ({drawdown:.1%} drawdown) - {block_status}")
# 4. VaR Calculation
print("\n4. Value at Risk (VaR) Calculation:")
print("-" * 60)
var_calc = PortfolioVaR(
confidence_level=0.95,
var_limit_pct=0.05,
)
# Simulate different volatility scenarios
scenarios = [
("Low Volatility", [0.01, -0.005, 0.008, -0.003, 0.005]),
("Medium Volatility", [0.02, -0.015, 0.018, -0.012, 0.015]),
("High Volatility", [0.05, -0.04, 0.06, -0.05, 0.045]),
]
portfolio_value = 10000.0
for name, returns in scenarios:
var_result = var_calc.calculate_var(
portfolio_value=portfolio_value,
returns=returns
)
var_pct = var_result.var_amount / portfolio_value
within_limit = var_result.is_within_limit
status = "OK" if within_limit else "EXCEEDED"
print(f"\n {name}:")
print(f" VaR (95%): ${var_result.var_amount:,.2f} ({var_pct:.2%})")
print(f" Status: {status}")
# 5. Risk alerts
print("\n5. Risk Alert System:")
print("-" * 60)
from openclaw.portfolio.risk import RiskAlert, RiskAlertLevel
alerts = [
RiskAlert(
timestamp=datetime.now(),
alert_type="position_concentration",
level=RiskAlertLevel.WARNING,
message="AAPL position exceeds 20% limit",
symbol="AAPL",
current_value=0.25,
threshold=0.20,
action_taken="blocked",
),
RiskAlert(
timestamp=datetime.now(),
alert_type="drawdown",
level=RiskAlertLevel.CRITICAL,
message="Portfolio drawdown exceeds 10%",
symbol=None,
current_value=0.12,
threshold=0.10,
action_taken="trading_blocked",
),
]
for alert in alerts:
emoji = "⚠️" if alert.level == RiskAlertLevel.WARNING else "🚨"
print(f"\n {emoji} {alert.level.value.upper()}")
print(f" Type: {alert.alert_type}")
print(f" Message: {alert.message}")
print(f" Current: {alert.current_value:.1%}, Threshold: {alert.threshold:.1%}")
print(f" Action: {alert.action_taken}")
print("\n" + "=" * 60)
print("Portfolio risk example complete!")
print("=" * 60)
if __name__ == "__main__":
main()