RiskStop / app.py
vincentiusyoshuac's picture
Create app.py
5ae4604 verified
import streamlit as st
import pandas as pd
import numpy as np
import plotly.graph_objects as go
import plotly.express as px
from datetime import datetime, timedelta
import json
# Custom CSS with Tailwind-like utilities
def load_css():
st.markdown("""
<style>
/* Tailwind-inspired utilities */
.dashboard-card {
background-color: white;
border-radius: 0.5rem;
padding: 1.5rem;
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1);
margin-bottom: 1rem;
}
.metric-card {
background-color: #f8fafc;
border-radius: 0.375rem;
padding: 1rem;
margin: 0.5rem 0;
border: 1px solid #e2e8f0;
}
.metric-title {
color: #64748b;
font-size: 0.875rem;
font-weight: 500;
margin-bottom: 0.5rem;
}
.metric-value {
color: #1e293b;
font-size: 1.5rem;
font-weight: 600;
}
.risk-high {
color: #dc2626;
}
.risk-moderate {
color: #d97706;
}
.risk-low {
color: #059669;
}
/* Custom Streamlit modifications */
.stApp {
background-color: #f1f5f9;
}
.css-1d391kg {
padding: 1rem 1rem;
}
</style>
""", unsafe_allow_html=True)
class FinancialDashboard:
def __init__(self):
self.risk_analyzer = FinancialRiskAnalyzer()
load_css()
def run(self):
st.set_page_config(
page_title="Financial Risk Analysis Dashboard",
page_icon="πŸ“Š",
layout="wide"
)
# Sidebar
self.create_sidebar()
# Main dashboard
st.title("πŸ“Š Financial Risk Analysis Dashboard")
# Load sample or uploaded data
financial_data = self.load_financial_data()
if financial_data:
# Generate risk report
risk_report = self.risk_analyzer.generate_risk_report(financial_data)
# Display dashboard components
self.display_risk_summary(risk_report)
self.display_detailed_metrics(risk_report)
self.display_risk_charts(financial_data, risk_report)
self.display_recommendations(risk_report)
def create_sidebar(self):
with st.sidebar:
st.title("Controls & Filters")
# Date range selector
st.subheader("Date Range")
start_date = st.date_input(
"Start Date",
datetime.now() - timedelta(days=30)
)
end_date = st.date_input(
"End Date",
datetime.now()
)
# Risk threshold adjustments
st.subheader("Risk Thresholds")
leverage_threshold = st.slider(
"Leverage Ratio Threshold",
min_value=10.0,
max_value=50.0,
value=30.0
)
npl_threshold = st.slider(
"NPL Ratio Threshold (%)",
min_value=1.0,
max_value=10.0,
value=5.0
) / 100
# Export options
st.subheader("Export Options")
if st.button("Export Report (PDF)"):
st.info("Generating PDF report...")
# Add PDF export functionality
if st.button("Export Data (Excel)"):
st.info("Generating Excel file...")
# Add Excel export functionality
def load_financial_data(self):
# File upload option
uploaded_file = st.file_uploader(
"Upload financial data (JSON/CSV)",
type=["json", "csv"]
)
if uploaded_file:
try:
if uploaded_file.type == "application/json":
return json.load(uploaded_file)
else:
df = pd.read_csv(uploaded_file)
return df.to_dict()
except Exception as e:
st.error(f"Error loading file: {str(e)}")
return None
# Use sample data if no file uploaded
return self.get_sample_data()
def display_risk_summary(self, risk_report):
st.subheader("Risk Summary")
# Create three columns for key metrics
col1, col2, col3 = st.columns(3)
with col1:
self.metric_card(
"Overall Risk Level",
risk_report['risk_level'],
self.get_risk_color(risk_report['risk_level'])
)
with col2:
self.metric_card(
"Risk Score",
f"{risk_report['risk_score']:.2f}",
self.get_risk_color(risk_report['risk_level'])
)
with col3:
self.metric_card(
"Total Alerts",
len(risk_report['risk_alerts']),
"risk-moderate" if len(risk_report['risk_alerts']) > 0 else "risk-low"
)
# Risk Alerts
if risk_report['risk_alerts']:
st.markdown("### ⚠️ Risk Alerts")
for alert in risk_report['risk_alerts']:
st.warning(alert)
def display_detailed_metrics(self, risk_report):
st.subheader("Detailed Metrics")
# Create tabs for different metric categories
tabs = st.tabs([
"Basic Ratios",
"Funding Risk",
"Asset Quality",
"Market Risk",
"Operational Risk"
])
# Basic Ratios Tab
with tabs[0]:
metrics = risk_report['detailed_metrics']['basic_ratios']
self.create_metrics_grid(metrics)
# Funding Risk Tab
with tabs[1]:
metrics = risk_report['detailed_metrics']['funding_risks']
self.create_metrics_grid(metrics)
# Asset Quality Tab
with tabs[2]:
metrics = risk_report['detailed_metrics']['asset_risks']
self.create_metrics_grid(metrics)
# Market Risk Tab
with tabs[3]:
metrics = risk_report['detailed_metrics']['market_risks']
self.create_metrics_grid(metrics)
# Operational Risk Tab
with tabs[4]:
metrics = risk_report['detailed_metrics']['operational_risks']
self.create_metrics_grid(metrics)
def display_risk_charts(self, financial_data, risk_report):
st.subheader("Risk Analysis Charts")
# Create two columns for charts
col1, col2 = st.columns(2)
with col1:
# Radar chart for key risk indicators
self.create_radar_chart(risk_report)
with col2:
# Time series chart for trending metrics
self.create_trend_chart(financial_data)
# Additional charts in new row
col3, col4 = st.columns(2)
with col3:
# Asset composition pie chart
self.create_asset_composition_chart(financial_data)
with col4:
# Funding structure chart
self.create_funding_structure_chart(financial_data)
def display_recommendations(self, risk_report):
st.subheader("Recommendations & Actions")
# Generate recommendations based on risk levels
recommendations = self.generate_recommendations(risk_report)
for category, rec_list in recommendations.items():
with st.expander(f"πŸ“‹ {category}"):
for rec in rec_list:
st.markdown(f"- {rec}")
def metric_card(self, title, value, risk_class):
st.markdown(f"""
<div class="metric-card">
<div class="metric-title">{title}</div>
<div class="metric-value {risk_class}">{value}</div>
</div>
""", unsafe_allow_html=True)
def create_metrics_grid(self, metrics):
cols = st.columns(2)
for idx, (metric, value) in enumerate(metrics.items()):
with cols[idx % 2]:
self.metric_card(
self.format_metric_name(metric),
f"{value:.2%}" if isinstance(value, float) else value,
self.get_metric_risk_color(metric, value)
)
def create_radar_chart(self, risk_report):
# Extract key risk indicators
metrics = risk_report['detailed_metrics']['basic_ratios']
fig = go.Figure()
categories = list(metrics.keys())
values = list(metrics.values())
fig.add_trace(go.Scatterpolar(
r=values,
theta=categories,
fill='toself',
name='Current'
))
fig.update_layout(
polar=dict(
radialaxis=dict(
visible=True,
range=[0, 1]
)
),
showlegend=False
)
st.plotly_chart(fig, use_container_width=True)
def create_trend_chart(self, financial_data):
# Create sample trend data
dates = pd.date_range(end=datetime.now(), periods=30, freq='D')
trend_data = pd.DataFrame({
'Date': dates,
'Risk Score': np.random.uniform(2, 6, 30)
})
fig = px.line(
trend_data,
x='Date',
y='Risk Score',
title='Risk Score Trend'
)
st.plotly_chart(fig, use_container_width=True)
def create_asset_composition_chart(self, financial_data):
# Extract asset composition
assets = {
'Corporate Loans': financial_data.get('corporate_loans', 0),
'Retail Loans': financial_data.get('retail_loans', 0),
'Securities': financial_data.get('securities', 0),
'Interbank Assets': financial_data.get('interbank_assets', 0)
}
fig = px.pie(
values=list(assets.values()),
names=list(assets.keys()),
title='Asset Composition'
)
st.plotly_chart(fig, use_container_width=True)
def create_funding_structure_chart(self, financial_data):
# Extract funding structure
funding = {
'Retail Deposits': financial_data.get('retail_deposits', 0),
'Corporate Deposits': financial_data.get('corporate_deposits', 0),
'Wholesale Funding': financial_data.get('wholesale_funding', 0),
'Interbank Borrowing': financial_data.get('interbank_borrowing', 0)
}
fig = px.bar(
x=list(funding.keys()),
y=list(funding.values()),
title='Funding Structure'
)
st.plotly_chart(fig, use_container_width=True)
@staticmethod
def get_risk_color(risk_level):
colors = {
'CRITICAL': 'risk-high',
'HIGH': 'risk-high',
'MODERATE': 'risk-moderate',
'LOW': 'risk-low'
}
return colors.get(risk_level, 'risk-low')
@staticmethod
def get_metric_risk_color(metric, value):
# Add logic to determine color based on metric type and value
return 'risk-moderate'
@staticmethod
def format_metric_name(metric):
return metric.replace('_', ' ').title()
@staticmethod
def generate_recommendations(risk_report):
recommendations = {
'Immediate Actions': [
'Review and adjust leverage levels',
'Strengthen liquidity buffers',
'Enhance risk monitoring systems'
],
'Medium-term Improvements': [
'Develop comprehensive risk management framework',
'Implement stress testing scenarios',
'Review counterparty exposure limits'
],
'Long-term Strategy': [
'Diversify funding sources',
'Strengthen capital adequacy',
'Enhance risk reporting systems'
]
}
return recommendations
@staticmethod
def get_sample_data():
return {
'total_debt': 500000000,
'equity': 150000000,
'non_performing_loans': 25000000,
'total_loans': 400000000,
'loan_loss_provisions': 15000000,
'total_assets': 700000000,
'current_assets': 200000000,
'current_liabilities': 180000000,
'total_capital': 120000000,
'risk_weighted_assets': 500000000,
'short_term_funding': 300000000,
'total_funding': 600000000,
'wholesale_funding': 200000000,
'retail_deposits': 250000000,
'corporate_deposits': 150000000,
'interbank_borrowing': 100000000,
'long_term_funding': 200000000,
'level_3_assets': 50000000,
'derivative_notional': 400000000,
'contingent_liabilities': 80000000,
'undrawn_commitments': 120000000,
'var_99': 10000000,
'interest_rate_gap': 30000000,
'net_forex_position': 15000000,
'market_correlation': 0.6,
'process_risk_score': 0.04,
'system_risk_score': 0.03,
'compliance_risk_score': 0.02,
'fraud_risk_score': 0.03,
'collateral_coverage': 0.85,
'current_npl': 25000000,
'previous_npl': 20000000,
'corporate_loans': 200000000,
'retail_loans': 150000000,
'securities': 100000000,
'interbank_assets': 50000000
}
# Main app file (app.py)
def main():
dashboard = FinancialDashboard()
dashboard.run()
if __name__ == "__main__":
main()