Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "Abhishek-tools",
"owner": {
"name": "Abhishek",
"email": "abgupta@yahoo.com"
},

"plugins": [
{
"name": "independent-reviewer",
"source": "./independent-reviewer",
"description": "Carry out an independent review of all changes since last commit",
"version": "1.0.0",
"author": {
"name": "Abhishek"
}
}
]
}
3 changes: 3 additions & 0 deletions .claude/agent-memory/commit-diff-reviewer/MEMORY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Agent Memory Index

- [User Profile](user_profile.md) — Senior developer building FinAlly AI trading workstation; prefers terse, direct feedback
6 changes: 6 additions & 0 deletions .claude/agents/change-reviewer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
name: change-reviewer
description: Carry out a comprehensive review of all changes since last commit
---

The sub agent reviews all changes since the last commit. Write your results to planning/SINCE-COMMIT-REVIEW2.md
10 changes: 10 additions & 0 deletions .claude/agents/codex-reviewer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
name: codex-reviewer
description: Carry out a comprehensive review of PLAN.md when requested using codex
---

You are using a different AI Agent to carry out a review of the document: planning/PLAN.md.
You MUST execute the following shell command to carry out the review - do not review yourself:
`codex exec "Please review the file planning/PLAN.md and write your results to planning/REVIEW.md"`
This will run the review process and save the results.
Do not review yourself.
224 changes: 224 additions & 0 deletions .claude/agents/commit-diff-reviewer.md

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions .claude/commands/doc-review.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Review the documentation file in the planning folder called $ARGUMENTS and add questions, clarifications, or feedback to a new section at the end, along with any opportunities to simplify.
3 changes: 2 additions & 1 deletion .claude/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"enabledPlugins": {
"frontend-design@claude-plugins-official": true,
"context7@claude-plugins-official": true,
"playwright@claude-plugins-official": true
"playwright@claude-plugins-official": true,
"independent-reviewer@Abhishek-tools": true
}
}
2 changes: 1 addition & 1 deletion .claude/skills/cerebras/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
name: cerebras-inference
name: cerebras
description: Use this to write code to call an LLM using LiteLLM and OpenRouter with the Cerebras inference provider
---

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/claude.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,5 @@ jobs:
# Optional: Add claude_args to customize behavior and configuration
# See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
# or https://code.claude.com/docs/en/cli-reference for available options
# claude_args: '--allowed-tools Bash(gh pr:*)'
# claude_args: '--allowed-tools Bash(gh pr *)'

3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -205,3 +205,6 @@ cython_debug/
marimo/_static/
marimo/_lsp/
__marimo__/

# Claude Code local settings
.claude/settings.local.json
76 changes: 34 additions & 42 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,62 +1,54 @@
# FinAlly — AI Trading Workstation

A visually stunning AI-powered trading workstation that streams live market data, simulates portfolio trading, and integrates an LLM chat assistant that can analyze positions and execute trades via natural language.
A Bloomberg-terminal-inspired trading simulator with live market data and an AI assistant that can analyze your portfolio and execute trades via natural language.

Built entirely by coding agents as a capstone project for an agentic AI coding course.

## Features

- **Live price streaming** via SSE with green/red flash animations
- **Simulated portfolio** — $10k virtual cash, market orders, instant fills
- **Portfolio visualizations** — heatmap (treemap), P&L chart, positions table
- **AI chat assistant** — analyzes holdings, suggests and auto-executes trades
- **Watchlist management** — track tickers manually or via AI
- **Dark terminal aesthetic** — Bloomberg-inspired, data-dense layout
## Quick Start

## Architecture
```bash
cp .env.example .env
# Edit .env: add OPENROUTER_API_KEY (required), MASSIVE_API_KEY (optional)
./scripts/start_mac.sh
```

Single Docker container serving everything on port 8000:
Open [http://localhost:8000](http://localhost:8000).

- **Frontend**: Next.js (static export) with TypeScript and Tailwind CSS
- **Backend**: FastAPI (Python/uv) with SSE streaming
- **Database**: SQLite with lazy initialization
- **AI**: LiteLLM → OpenRouter (Cerebras inference) with structured outputs
- **Market data**: Built-in GBM simulator (default) or Massive API (optional)
## Features

## Quick Start
- **Live price streaming** via SSE — prices flash green/red on change
- **Simulated portfolio** — $10k virtual cash, market orders, instant fill
- **Sparklines & charts** — per-ticker mini-charts and a detailed main chart
- **Portfolio heatmap** — treemap sized by weight, colored by P&L
- **AI chat** — ask questions, get analysis, execute trades in plain English

```bash
# Clone and configure
cp .env.example .env
# Add your OPENROUTER_API_KEY to .env
## Architecture

# Run with Docker
docker build -t finally .
docker run -v finally-data:/app/db -p 8000:8000 --env-file .env finally
Single Docker container, single port (8000):

# Open http://localhost:8000
```
- **Frontend**: Next.js static export, served by FastAPI
- **Backend**: FastAPI + Python (uv), SQLite database
- **Market data**: GBM simulator by default; Massive/Polygon.io API if `MASSIVE_API_KEY` is set
- **AI**: LiteLLM → OpenRouter (Cerebras), structured outputs for trade execution

## Environment Variables

| Variable | Required | Description |
|---|---|---|
| `OPENROUTER_API_KEY` | Yes | OpenRouter API key for AI chat |
| `MASSIVE_API_KEY` | No | Massive (Polygon.io) key for real market data; omit to use simulator |
| `LLM_MOCK` | No | Set `true` for deterministic mock LLM responses (testing) |
| `OPENROUTER_API_KEY` | Yes | LLM inference via OpenRouter |
| `MASSIVE_API_KEY` | No | Real market data; simulator used if unset |
| `LLM_MOCK` | No | Set `true` for deterministic mock responses (testing) |

## Project Structure
## Development

```
finally/
├── frontend/ # Next.js static export
├── backend/ # FastAPI uv project
├── planning/ # Project documentation and agent contracts
├── test/ # Playwright E2E tests
├── db/ # SQLite volume mount (runtime)
└── scripts/ # Start/stop helpers
```bash
# Backend tests
cd backend && uv run pytest -v

# Frontend
cd frontend && npm install && npm run dev
```

## License
## Running Tests (E2E)

See [LICENSE](LICENSE).
```bash
cd test && docker compose -f docker-compose.test.yml up
```
Binary file added independent-reviewer/.DS_Store
Binary file not shown.
5 changes: 5 additions & 0 deletions independent-reviewer/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "independent-reviewer",
"description": "Carry out an independent review of all changes since last commit",
"version": "1.0.0"
}
Binary file added independent-reviewer/hooks/.DS_Store
Binary file not shown.
15 changes: 15 additions & 0 deletions independent-reviewer/hooks/hooks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"hooks": {
"Stop": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "git status"
}
]
}
]
}
}
54 changes: 54 additions & 0 deletions planning/DECISIONS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Planning Decisions

This file records concrete decisions made to resolve open questions and contract gaps in `planning/PLAN.md`.

## 2026-04-13

### LLM configuration

- `OPENROUTER_API_KEY` is required only when `LLM_MOCK=false`.
- `LLM_MOCK=true` is a supported no-key development and test mode.
- The backend should fail fast at startup if mock mode is off and the API key is missing.

Reasoning: this preserves the intended low-friction local and CI workflow while keeping production configuration errors obvious.

### Docker persistence

- Local development and test runs use a bind mount from repo `db/` to `/app/db`.
- The plan no longer mixes bind mounts with a named Docker volume.
- `db/finally.db` is intentionally visible on the host for inspection and persistence.

Reasoning: one persistence model is easier for agents to implement consistently, and host-visible SQLite data is useful for a course project.

### Chat API contract

- `/api/chat` returns persisted `user_message` and `assistant_message` objects, including message IDs and timestamps.
- Action results are returned only after execution, under `assistant_message.actions`.
- Partial failures are represented per action with `status` plus `error`, while the overall response remains `200` for valid requests.
- The response also includes post-execution `portfolio` and `watchlist` state so the frontend can reconcile immediately.

Reasoning: this removes frontend/backend ambiguity around inline confirmations, persisted message identity, and partial trade failures.

### Position lifecycle

- Selling a position to zero keeps the row but resets `avg_cost` to `0`.
- A later buy in the same ticker establishes a brand-new cost basis.

Reasoning: unrealized P&L after re-entry should reflect only the new position, not stale historical basis.

### Trade validation

- Tickers are normalized to uppercase and trimmed.
- Unsupported symbols are rejected.
- Quantity must be finite, positive, and no more than 4 decimal places.
- Manual and LLM-originated trades use the exact same validation rules.

Reasoning: shared validation rules prevent drift between frontend behavior, direct API usage, and AI-triggered actions.

### SSE protocol

- `/api/stream/prices` uses named SSE events: `snapshot`, `price`, `watchlist`, and `heartbeat`.
- The server sends an initial `snapshot` immediately on connect.
- Watchlist add/remove operations emit a `watchlist` event on existing connections rather than requiring reconnect.

Reasoning: explicit event types give frontend and backend a stable contract for initial render, live updates, and reconnect behavior.
Loading