A fullstack autonomous trading application that uses AI agents to analyze market data and execute trades through brokerage APIs.
┌─────────────────────────────────────────────────────────────┐
│ Frontend (React + Vite) │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Balance │ │ Operations │ │ Stocks │ │
│ │ Component │ │ Component │ │ Component │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
REST API (HTTP)
│
┌─────────────────────────────────────────────────────────────┐
│ Backend (Go + Gin) │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ API Handlers │ │
│ └──────────────────────────────────────────────────────┘ │
│ │ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Core Agent │ │ Tools │ │ Brokerage │ │
│ │ (Multi-LLM) │ │ │ │ Manager │ │
│ │ │ │ - Brokerage│ │ │ │
│ │ - OpenAI │ │ - News │ │ - Mock │ │
│ │ - DeepSeek │ │ - Web Search│ │ - Robinhood │ │
│ │ - TogetherAI │ │ - Procedures│ │ │ │
│ │ - Anthropic │ │ - Reflection│ │ │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ SQLite │ │ ChromaDB │ │ News │ │
│ │ (Storage) │ │ (Vectors) │ │ Manager │ │
│ │ │ │ │ │ │ │
│ │ - Operations │ │ │ │ - NewsAPI │ │
│ │ - Positions │ │ │ │ - Massive │ │
│ │ - Threads │ │ │ │ - Brave │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────────┘
- Balance View: See current cash balance and total portfolio value in real-time
- Operations History: Review all trades made by the agent with detailed reasoning for each decision
- Stock Holdings: Monitor current positions with P/L calculations
- Multi-Provider LLM Support: Easily swap between OpenAI, DeepSeek, TogetherAI, and Anthropic Claude
- Agent Interface: Common abstraction for different AI providers
- Factory Pattern: Simple configuration-based provider selection
- Conversation Memory: Persistent conversation history with thread management
- Tool System: Extensible tool framework with dynamic tool loading
- Brokerage Tool: Account operations (balance, positions, trade history, prices, execute trades)
- Financial News Tool: Fetch news from multiple sources for stock symbols
- Web Search Tool: General web search using Brave Search API (when configured)
- Procedures Tool: Multi-step stock analysis procedures with isolated agent instances
- Reflection Tool: Inspect runtime context (model, thread ID)
- Foo Tool: Test/debugging tool
- BrokerageManager: Centralized provider registration and initialization
- Mock Trading Service: Simulated trading environment for development and testing ($10k default balance)
- Robinhood Integration: Real crypto trading API integration (BTC, ETH, DOGE, etc.)
- Broker Interface: Easy addition of new brokerage services
- Manager Pattern: Dynamic provider registration without code changes
- NewsManager: Centralized provider registration and initialization
- NewsAPI.org: General financial news articles
- Massive: News with sentiment analysis and ticker extraction
- Brave Search: Web search API for general information and news
- Aggregator Pattern: Combines multiple sources with graceful degradation
- Manager Pattern: Dynamic provider registration without code changes
- SQLite: Local database for trade history, positions, balance, and conversation threads
- ChromaDB: Vector database for semantic search of news and market data (simplified in-memory implementation)
thinktwice-agent/
├── backend/
│ ├── cmd/
│ │ └── server/
│ │ └── main.go # Application entry point
│ ├── internal/
│ │ ├── agent/
│ │ │ ├── interface.go # Agent interface definition
│ │ │ ├── openai.go # OpenAI implementation
│ │ │ ├── deepseek.go # DeepSeek implementation (OpenAI-compatible)
│ │ │ ├── together.go # TogetherAI implementation (OpenAI-compatible)
│ │ │ ├── factory.go # Provider factory
│ │ │ ├── memory.go # Conversation memory/persistence
│ │ │ ├── system.go # System message manager
│ │ │ ├── models.go # Data models (messages, threads)
│ │ │ └── context.go # Context management
│ │ ├── brokerage/
│ │ │ ├── interface.go # Broker interface
│ │ │ ├── manager.go # Brokerage provider manager
│ │ │ ├── mock.go # Mock trading service
│ │ │ └── robinhood.go # Robinhood crypto implementation
│ │ ├── news/
│ │ │ ├── interface.go # News source interface
│ │ │ ├── manager.go # News provider manager
│ │ │ ├── newsapi.go # NewsAPI.org client
│ │ │ ├── massive.go # Massive news API client
│ │ │ └── brave.go # Brave Search API client
│ │ ├── tool/
│ │ │ ├── interface.go # Tool interface
│ │ │ ├── manager.go # Tool manager (builds default toolset)
│ │ │ ├── newsTool.go # News fetching tool (financial_news)
│ │ │ ├── brokerageTool.go # Brokerage operations tool (brokerage_account)
│ │ │ ├── webTool.go # Web search tool (web_search)
│ │ │ ├── reflectionTool.go # Reflection tool (reflection)
│ │ │ ├── fooTool.go # Test tool (foo_tool)
│ │ │ ├── procedures/ # Procedures system
│ │ │ │ ├── tool.go # Procedures tool (procedures)
│ │ │ │ ├── types.go # Procedure type definitions
│ │ │ │ ├── loader.go # Procedure instruction loader
│ │ │ │ └── gather_symbol_informations.md # Procedure instructions
│ │ │ └── procedures_registry.go # Procedure tool registration
│ │ ├── config/
│ │ │ ├── manager.go # ConfigManager orchestrator
│ │ │ ├── interface.go # Config interface
│ │ │ ├── llm_provider.go # LLM configuration
│ │ │ ├── news_agg.go # News aggregation config
│ │ │ ├── brokerage.go # Brokerage configuration
│ │ │ ├── database.go # Database paths config
│ │ │ ├── server.go # Server settings config
│ │ │ └── models.go # Config database models
│ │ ├── database/
│ │ │ ├── sqlite.go # Database connection and operations
│ │ │ └── models.go # Data models
│ │ ├── vectordb/
│ │ │ └── chroma.go # ChromaDB integration
│ │ └── api/
│ │ ├── handlers.go # HTTP handlers
│ │ └── routes.go # Route definitions
│ ├── .env.example # Environment variables template
│ ├── go.mod # Go dependencies
│ └── go.sum # Dependency checksums
├── frontend/
│ ├── src/
│ │ ├── components/
│ │ │ ├── Balance.tsx # Balance display component
│ │ │ ├── Operations.tsx # Trade history component
│ │ │ └── Stocks.tsx # Holdings component
│ │ ├── services/
│ │ │ └── api.ts # API client
│ │ ├── types/
│ │ │ └── index.ts # TypeScript types
│ │ ├── App.tsx # Main application component
│ │ ├── main.tsx # Entry point
│ │ └── index.css # Global styles
│ ├── public/
│ ├── index.html
│ ├── package.json # Node dependencies
│ ├── vite.config.ts # Vite configuration
│ ├── tsconfig.json # TypeScript configuration
│ ├── tailwind.config.js # Tailwind CSS configuration
│ ├── postcss.config.js # PostCSS configuration
│ └── .env.example # Frontend environment variables
└── README.md # This file
- Go 1.21 or higher
- Node.js 18 or higher
- npm or yarn
-
Navigate to backend directory:
cd backend -
Install Go dependencies:
go mod download
-
Configure environment variables (optional):
The application works without configuration (using mock broker and defaults). Configuration can be managed in two ways:
Primary Method: UI Configuration
The recommended way to configure the application is through the web UI. Once the frontend is running, navigate to the Configuration page where you can:
- Add and manage LLM provider configurations (OpenAI, DeepSeek, TogetherAI, Anthropic)
- Configure news service APIs (NewsAPI, Massive, Brave Search)
- Set up brokerage settings (Mock or Robinhood)
- All configurations are saved to the database and persist across restarts
Alternative Method: Environment Variables (for troubleshooting)
Environment variables override any configuration stored in the database and are primarily intended for troubleshooting or temporary overrides. To use environment variables:
cp .env.example .env
Edit
.envand add your API keys:# LLM Provider Configuration (optional) AGENT_PROVIDER=openai # Options: openai, deepseek, together OPENAI_API_KEY=your_key_here # For OpenAI DEEPSEEK_API_KEY=your_key_here # For DeepSeek TOGETHER_API_KEY=your_key_here # For TogetherAI AGENT_MODEL=gpt-5 # Override default model AGENT_TEMPERATURE=0.7 # 0.0-2.0 AGENT_MAX_TOKENS=2000 # Max response tokens # News API Keys (optional) NEWSAPI_KEY=your_key_here # NewsAPI.org MASSIVE_API_KEY=your_key_here # Massive news API BRAVE_API_KEY=your_key_here # Brave Search API (for web search tool) # Brokerage Configuration (optional) BROKER_SERVICE=mock # Options: mock, robinhood MOCK_INITIAL_BALANCE=10000.0 # Starting balance for mock broker MOCK_COMMISSION_RATE=0.0 # Commission percentage ROBINHOOD_API_KEY=your_key_here # For Robinhood crypto trading ROBINHOOD_PRIVATE_KEY=your_key_here # For Robinhood crypto trading # Database (optional, has defaults) SQLITE_PATH=./data/trading.db CHROMA_PATH=./data/chroma # Server (optional, has defaults) PORT=8080 GIN_MODE=debug
Configuration Priority:
- Environment variables (highest priority - overrides database settings)
- Database-persisted settings (configured via UI)
- Default values (if neither available)
Note: Environment variables are meant for troubleshooting and temporary overrides. For persistent configuration, use the UI which saves settings to the database.
-
Run the server:
go run cmd/server/main.go
The backend will start on
http://localhost:8080
-
Navigate to frontend directory:
cd frontend -
Install dependencies:
npm install
-
Configure environment variables:
cp .env.example .env
Edit
.env:VITE_API_URL=http://localhost:8080
-
Run the development server:
npm run dev
The frontend will start on
http://localhost:5173
Returns the current account balance.
Response:
{
"cash": 10000.00,
"portfolio_value": 5000.00,
"total": 15000.00
}Returns the trade history with reasoning.
Query Parameters:
limit(optional): Number of operations to return (default: 50)offset(optional): Pagination offset
Response:
{
"operations": [
{
"id": 1,
"timestamp": "2025-11-22T10:30:00Z",
"stock_symbol": "AAPL",
"action": "BUY",
"quantity": 10,
"price": 150.25,
"reasoning": "Strong earnings report and positive market sentiment..."
}
]
}Returns current stock holdings.
Response:
{
"positions": [
{
"symbol": "AAPL",
"quantity": 10,
"avg_cost": 150.25,
"current_price": 155.00,
"total_value": 1550.00,
"profit_loss": 47.50,
"profit_loss_percent": 3.16
}
]
}Returns all application configurations summary.
Response:
{
"config": {
"llm_provider": {
"available": true,
"provider": "openai",
"model": "gpt-4"
},
"news_aggregation": {
"available": true,
"sources": ["NewsAPI", "Massive"]
},
"brokerage": {
"available": true,
"service": "mock",
"is_mock": true
}
}
}Stream chat with the AI agent via Server-Sent Events (SSE).
Request Body:
{
"thread_id": 0,
"content": "What's the current balance?"
}Response: SSE stream with message, error, and done events.
Returns paginated list of conversation threads.
Query Parameters:
limit(optional): Number of threads to return (default: 20)offset(optional): Pagination offset
Returns a specific thread with full message history.
Stops an ongoing chat stream for a specific thread.
Creates a new LLM provider configuration.
Returns all saved LLM provider configurations.
Activates a specific LLM provider configuration.
Creates or updates brokerage configuration.
Returns current brokerage configuration.
Creates or updates a news service configuration.
Returns all news service configurations.
Activates or deactivates a news service configuration.
The application uses a ConfigManager for centralized configuration management with multiple configuration sources:
Configuration Methods:
-
UI Configuration (recommended): Configure settings through the web UI at the Configuration page. All settings are saved to the database and persist across restarts.
-
Environment Variables (for troubleshooting): Environment variables override database settings and are primarily intended for troubleshooting or temporary overrides. They take precedence over any configuration stored in the database.
-
Database Tables (persisted settings): Settings configured via the UI are stored here and persist across restarts.
-
Default Values (safe fallbacks): Used when no configuration is available.
Priority Order:
- Environment Variables (highest priority - overrides database)
- Database-persisted settings (from UI)
- Default Values (if neither available)
Documentation: config/README.md
Controls AI agent behavior:
AGENT_PROVIDER=openai # Options: openai, deepseek, together
OPENAI_API_KEY=sk-your-key # For OpenAI
DEEPSEEK_API_KEY=sk-your-key # For DeepSeek
TOGETHER_API_KEY=your-key # For TogetherAI
AGENT_MODEL=gpt-4 # Optional: override default model
AGENT_TEMPERATURE=0.7 # Optional: 0.0-2.0
AGENT_MAX_TOKENS=2000 # Optional: max response tokens- OpenAI: Requires
OPENAI_API_KEY, supports GPT-4, GPT-3.5, etc. - DeepSeek: Requires
DEEPSEEK_API_KEY, uses OpenAI-compatible API - TogetherAI: Requires
TOGETHER_API_KEY, uses OpenAI-compatible API - If not configured: AI features disabled, manual trading only
- Multiple Configs: Supports multiple saved configurations with one active at a time
Enables market news analysis:
NEWSAPI_KEY=your-key # NewsAPI.org (100 req/day free)
MASSIVE_API_KEY=your-key # Massive news API (with sentiment analysis)- NewsAPI.org: General financial news articles
- Massive: News with sentiment analysis and ticker extraction
- If not configured: News-based analysis disabled
- Multiple Services: Supports multiple news service configurations with individual activation
Trading execution backend:
BROKER_SERVICE=mock # Options: mock, robinhood
MOCK_INITIAL_BALANCE=10000.0 # Mock broker starting balance
MOCK_COMMISSION_RATE=0.0 # Mock commission percentage
ROBINHOOD_API_KEY=your-key # For Robinhood integration
ROBINHOOD_PRIVATE_KEY=your-key # For Robinhood integration- Default: Mock broker ($10,000 balance, safe testing)
- Always available: Falls back to mock if not configured
Storage paths:
SQLITE_PATH=./data/trading.db # SQLite database file
CHROMA_PATH=./data/chroma # ChromaDB directory- Always available: Uses default paths if not configured
Server settings:
PORT=8080 # HTTP server port
GIN_MODE=debug # Options: debug, release- Always available: Uses port 8080, debug mode by default
Configurations can be saved to the database for reuse:
// Example: Save configuration programmatically
configMgr.GetLLMProviderConfig().Provider = "anthropic"
configMgr.SaveAll() // Persists to database
// Next startup will use database values if env vars not setThe application works out of the box with no configuration:
# No .env file needed!
go run cmd/server/main.goDefault behavior:
- Mock broker with $10,000
- No AI features (manual trading only)
- Server on port 8080
- SQLite at
./data/trading.db
Backend:
cd backend
go test ./...Frontend:
cd frontend
npm testBackend:
cd backend
go build -o trading-bot cmd/server/main.go
./trading-botFrontend:
cd frontend
npm run build
npm run previewCREATE TABLE operations (
id INTEGER PRIMARY KEY AUTOINCREMENT,
timestamp DATETIME NOT NULL,
stock_symbol TEXT NOT NULL,
action TEXT NOT NULL, -- BUY, SELL
quantity INTEGER NOT NULL,
price REAL NOT NULL,
reasoning TEXT NOT NULL
);CREATE TABLE positions (
symbol TEXT PRIMARY KEY,
quantity INTEGER NOT NULL,
avg_cost REAL NOT NULL
);CREATE TABLE balance (
id INTEGER PRIMARY KEY CHECK (id = 1), -- Single row
current_balance REAL NOT NULL
);The ConfigManager system uses these tables (auto-created):
-- LLM Provider Configuration (supports multiple configs, one active)
CREATE TABLE llm_provider_config (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT,
provider TEXT NOT NULL,
model TEXT,
api_key TEXT,
extra_config TEXT, -- JSON for temperature, max_tokens, etc.
is_active BOOLEAN DEFAULT false
);
-- News Aggregation Configuration (supports multiple services)
CREATE TABLE news_agg_config (
id INTEGER PRIMARY KEY AUTOINCREMENT,
service_name TEXT NOT NULL,
credentials TEXT, -- JSON map of credentials
active BOOLEAN DEFAULT false
);
-- Brokerage Configuration (singleton)
CREATE TABLE brokerage_config (
id INTEGER PRIMARY KEY CHECK (id = 1),
service TEXT,
initial_balance REAL,
commission_rate REAL,
robinhood_api_key TEXT,
robinhood_priv_key TEXT
);
-- Database Configuration (singleton)
CREATE TABLE database_config (
id INTEGER PRIMARY KEY CHECK (id = 1),
sqlite_path TEXT,
chroma_path TEXT
);
-- Server Configuration (singleton)
CREATE TABLE server_config (
id INTEGER PRIMARY KEY CHECK (id = 1),
port INTEGER,
gin_mode TEXT
);The agent system uses these tables for conversation persistence:
-- Threads: Conversation threads
CREATE TABLE threads (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT,
created_at DATETIME NOT NULL,
last_activity DATETIME NOT NULL,
deleted_at DATETIME
);
-- Messages: Individual messages within threads
CREATE TABLE messages (
id INTEGER PRIMARY KEY AUTOINCREMENT,
thread_id INTEGER NOT NULL,
role TEXT NOT NULL, -- "user", "assistant", "system"
content TEXT NOT NULL,
model TEXT,
tokens_sent INTEGER DEFAULT 0,
tokens_received INTEGER DEFAULT 0,
created_at DATETIME NOT NULL,
FOREIGN KEY (thread_id) REFERENCES threads(id) ON DELETE CASCADE
);- Initial architecture design
- Mock trading service
- Multi-provider agent system (OpenAI, DeepSeek, TogetherAI)
- News aggregation (NewsAPI, Massive)
- Vector database integration (ChromaDB)
- Basic frontend components
- API integration
- Real-time updates (SSE streaming)
- Robinhood API integration (crypto trading)
- Conversation memory and thread management
- Tool system (news, brokerage, web search, procedures, reflection)
- Multi-configuration support (LLM providers, news services)
- Manager pattern for news and brokerage providers
- Procedures system for multi-step stock analysis
- Web search tool with Brave Search integration
- Advanced trading strategies
- Backtesting capabilities
- Risk management rules
- Performance analytics dashboard
- Enhanced ChromaDB integration with proper embeddings
- Never commit API keys to version control
- Use environment variables for all sensitive data
- Rotate keys regularly
- Start with mock trading service
- Implement position size limits
- Add stop-loss mechanisms
- Require confirmation for large trades
- Check if port 8080 is available
- Verify API keys are set correctly
- Check Go version:
go version - Review logs for specific errors
- Ensure backend is running on port 8080
- Check CORS settings in backend
- Verify
VITE_API_URLin frontend.env
- Ensure ChromaDB directory is writable
- Check disk space
- Verify ChromaDB dependencies are installed
This is a single-user application designed for personal use. Future enhancements:
- Additional brokerage integrations
- More sophisticated trading strategies
- Multi-user support
- Cloud deployment options
Private project - All rights reserved
This software is for educational and simulation purposes. Trading stocks involves risk. The developers are not responsible for any financial losses incurred through the use of this software. Always test thoroughly with the mock trading service before connecting to real brokerage accounts.