FinSense is my first hackathon build: a small autonomous “financial copilot” that tries to turn market noise into one clear, simple action. It chats, runs a deterministic portfolio simulation, blends in market sentiment, and fires risk alerts. Then it gives a summary (≤180 words), one Action line, and a disclaimer so it’s clear this is just a demo. Why I built it? Most tools give static allocations and ignore context like sentiment swings or volatility spikes. I wanted something that stays inside risk bands, explains why it makes a suggestion, and doesn’t fall apart during a live demo.

What’s different (for me): Agent + guardrails: I mix LLM reasoning with deterministic sims and a fixed output schema. Risk-aware tweaks: I cap sentiment-based tilts at ±5% and always renormalise to 100%. Demo-stable: Seeded Monte Carlo and a simple 24-hour sentiment cache keep results predictable. AWS-first: Bedrock + Lambda/SageMaker + EventBridge + S3, so it’s modular and cheap to run.

How I put it together: Analytics core (Python): Seeded sims for allocation + KPIs (exp. return, vol, max drawdown). Sentiment module: Daily label (bearish/neutral/bullish) with confidence; cached for 24h. Risk rules: Volatility spike, sentiment flip, exposure mismatch → alert with severity + evidence + suggested action. Orchestrator: Validates inputs, calls the tools, and prompts the LLM to produce the short explanation + one action + disclaimer. UI (demo): Minimal form (risk, horizon, optional age, optional sentiment override) plus results (advice, pie, KPIs, alerts, “Advanced” raw JSON).

What I learned: Pairing an LLM with seeded Monte Carlo gives me “smart but stable.” Small, explainable rules beat fancy heuristics when time is tight. Short prompts + strict schemas keep outputs tidy and consistent.

Challenges: Keeping the advice consistent (solved with a fixed format + fallback). Avoiding over-reaction to headlines (band-guarded ±5% tilts). Time and cost (token caps, timeouts, daily cache).

A bit of math (copy-paste LaTeX)

Equity price dynamics (GBM, discrete form) St+Δt​=St​exp[(μ−21​σ2)Δt+σΔt​Zt​],Zt​∼N(0,1).

Portfolio path and maximum drawdown Let Pt be the portfolio value at step t. The maximum drawdown (MDD) over the path is MDD=0≤t≤Tmax​(max0≤u≤t​Pu​max0≤u≤t​Pu​−Pt​​).

Monte Carlo estimates (seeded for determinism) Generate N scenarios {Pt^(i)}^(T) t=0 with a fixed random seed. Define the 1-year return in scenario i as R^(i) 1y. then E[R1y​] = N1​i=1∑N​R1y(i)​, σ[R1y​]=N−11​i=1∑N​(R1y(i)​−E[R1y​])2

Portfolio composition With weights We, Wb, Wc for equities, bonds, and cash (so We + Wb + Wc = 1) , the scenario return mixes as R1y(i)​=we​Req(i)​+wb​Rbond(i)​+wc​Rcash(i)​.

Sentiment-aware tilt (band-guarded) Given a sentiment labels∈{bearish, neutral,bullish} with confidence c∈[0,1], I adjust equity weight by at most 5% scaled by c, staying inside the chosen risk band: Δwe​=⎩⎨⎧​−0.05c,0,+0.05c,​s=bearish,s=neutral,s=bullish.​ After applying ΔWe, I offset bonds/cash as needed and renormalise so We+Wb+Wc =1. I then recompute the KPIs on the tilted weights.

Built With

  • .env
  • ai
  • analytics/orchestrator)
  • bedrock
  • black
  • charts)-modeling-&-data-numpy
  • cloudwatch
  • config
  • dev
  • dev/test/deploy)
  • dotenv)
  • eventbridge
  • for
  • format/lint)
  • iam
  • kpi
  • lambda
  • languages-&-runtime-python-3.x-ui-streamlit-(chat-ui
  • llm
  • logs/metrics)
  • makefile
  • ops
  • orchestration
  • pandas-monte-carlo-simulation-(seeded)-json-schema-/-pydantic-(i/o-validation)-charts-plotly-(allocation-pie
  • pytest
  • quality
  • roles)
  • ruff
  • s3
  • sagemaker
  • scripts
  • tests)
  • ulid/uuid
  • unit/contract
Share this project:

Updates