Financial market data presents unique challenges for developers: it's real-time, constantly changing, and requires careful interpretation. This tutorial walks through building a REST API that combines live financial data with language models to create an intelligent market analysis service. We'll focus on creating a clean, maintainable architecture that can scale with your needs.
Architecture Overview
Before diving into the code, let's understand the key components of our system:
- Market Data Service: Handles all interactions with real-time financial data sources. This service abstracts away the complexity of fetching and formatting market data, providing a clean interface for the rest of our application.
- Assistant Service: Manages the language model interactions. It takes market data and user queries, then generates intelligent analysis based on current information. By separating this into its own service, we can easily swap out different language models or modify the prompting strategy.
- API Routes: Provides RESTful endpoints that combine the above services to handle user requests. The routes handle input validation, error handling, and response formatting.
Project Setup
First, let's set up our project structure. We'll use a modular approach that separates concerns and makes the code easier to test and maintain:
mkdir market-assistant-api
cd market-assistant-api
npm init -y
npm install express openai dotenv axios
You will need to get both an OpenAI API Key and a Pine API Key. With these, make sure to put them in the .env file.
PINE_API_KEY=your_pine_api_key
OPENAI_API_KEY=your_openai_api_key
PORT=3000
Now we can create this directory structure:
market-assistant-api/
├── src/
│ ├── services/
│ │ ├── marketData.js
│ │ └── assistant.js
│ └── server.js
├── .env
└── package.json
This structure separates our code into logical components, making it easier to maintain and test. The services directory contains our core business logic, while routes handles HTTP-specific concerns.
Implementation Details
Market Data Service (marketData.js)
This service encapsulates all market data operations. Each method is focused on a specific type of data retrieval:
getStockPrice
: Fetches current price and movement data for a single stock
getMarketTrends
: Retrieves sector-wide trend information
getComparisonData
: Gathers comparative data for multiple symbols
import axios from "axios";
class MarketDataService {
constructor(apiKey) {
this.client = axios.create({
baseURL: "https://api.pine.dev",
headers: {
Authorization: `Bearer ${apiKey}`,
"Content-Type": "application/json",
},
});
}
async makeQuery(query) {
const response = await this.client.post("/context", { query });
return response.data.markdown;
}
async getStockPrice(symbol) {
const query = `current price and daily movement for ${symbol} stock`;
const data = await this.makeQuery(query);
return data;
}
async getMarketTrends(sector) {
const query = `current market trends and performance for the ${sector} sector`;
const data = await this.makeQuery(query);
return data;
}
async getComparisonData(symbols) {
const symbolList = symbols.join(", ");
const query = `trends for each stock: ${symbolList}`;
const data = await this.makeQuery(query);
return data;
}
}
export default MarketDataService;
Assistant Service (assistant.js)
The Assistant Service handles the intelligence layer of our API. It takes market data and user queries and generates meaningful analysis:
import { OpenAI } from "openai";
class AssistantService {
constructor(apiKey) {
this.client = new OpenAI(apiKey);
}
async analyzeQuery(query, marketData) {
const systemPrompt = `
You are a financial analysis API. Analyze the following market data and answer the query.
Only use the provided market data for your analysis. If you can't answer something from
the provided data, say so explicitly.
Current Market Data:
${marketData}
`;
const completion = await this.client.chat.completions.create({
model: "gpt-4",
messages: [
{ role: "system", content: systemPrompt },
{ role: "user", content: query },
],
temperature: 0.3,
max_tokens: 2048,
});
return completion.choices[0].message.content;
}
}
export default AssistantService;
API Routes (server.js)
The API routes tie everything together, providing clean endpoints for clients to interact with:
import express from "express";
import dotenv from "dotenv";
import MarketDataService from "./services/marketData.js";
import AssistantService from "./services/assistant.js";
dotenv.config();
const router = express.Router();
const marketData = new MarketDataService(process.env.PINE_API_KEY);
const assistant = new AssistantService(process.env.OPENAI_API_KEY);
// Get analysis for a single stock
router.get("/analyze/stock/:symbol", async (req, res) => {
const { symbol } = req.params;
const { query } = req.query;
const data = await marketData.getStockPrice(symbol);
const analysis = await assistant.analyzeQuery(query, data);
res.json({
symbol,
analysis,
timestamp: new Date().toISOString(),
});
});
// Get sector analysis
router.get("/analyze/sector/:sector", async (req, res) => {
const { sector } = req.params;
const { query } = req.query;
const data = await marketData.getMarketTrends(sector);
const analysis = await assistant.analyzeQuery(query, data);
res.json({
sector,
analysis,
timestamp: new Date().toISOString(),
});
});
// Compare multiple stocks
router.post("/analyze/compare", async (req, res) => {
const { symbols, query } = req.body;
if (!Array.isArray(symbols) || symbols.length < 2) {
return res.status(400).json({
error: "Please provide at least two symbols to compare",
});
}
const data = await marketData.getComparisonData(symbols);
const analysis = await assistant.analyzeQuery(query, data);
res.json({
symbols,
analysis,
timestamp: new Date().toISOString(),
});
});
const app = express();
const port = process.env.PORT || 3000;
app.use(express.json());
app.use("/api", router);
app.listen(port, () => {
console.log(`Server is running on port http://localhost:${port}`);
});
API Usage
First, we must start the server
node ./src/server.js
Now, let's look at some practical examples of using it:
Analyzing a Single Stock
Request:
curl "http://localhost:3000/api/analyze/stock/AAPL?query=How%20has%20the%20stock%20performed%20today"
Response:
{
"symbol": "AAPL",
"analysis": "Based on the provided market data, Apple Inc. (AAPL) closed at $242.65, which is an increase of $3.06 or 1.28% from the previous close of $239.59. After hours, the stock price slightly increased by $0.10 or 0.04% to $242.75. The day's trading range was between $238.90 and $242.76.",
"timestamp": "2024-12-03T22:28:13.998Z"
}
Sector Analysis
Request:
curl "http://localhost:3000/api/analyze/sector/technology?query=What%20are%20the%20current%20sector%20trends"
Response:
{
"sector": "technology",
"analysis": "Based on the provided market data, the current sector trends in the technology industry for 2024 include:\n\n1. **Generative AI (Gen AI)**: This trend has seen significant growth...",
"timestamp": "2024-12-03T22:29:09.848Z"
}
Stock Comparison
Request:
curl -X POST "http://localhost:3000/api/analyze/compare" \
-H "Content-Type: application/json" \
-d '{
"symbols": ["AAPL", "MSFT", "GOOGL"],
"query": "Compare their performance today"
}'
Response:
{
"symbols": ["AAPL", "MSFT", "GOOGL"],
"analysis": "Based on the provided market data, here is the performance comparison for today:\n\n1. **Apple Inc. (AAPL)**\n - Current Price: $242.65\n - Change: +3.06 (1.28%)\n...",
"timestamp": "2024-12-03T22:31:31.991Z"
}
Next Steps
If you want to continue building with the API, these may be some good next steps:
Performance
To maintain good performance, consider implementing:
Caching Layer
Cache frequent queries
Store recent market data
Implement cache invalidation strategies
Rate Limiting
Limit requests per client
Implement token bucket algorithm
Add retry mechanisms
Request Optimization
Batch similar requests
Implement request queuing
Add request timeout handling
For Production
Authentication & Authorization
Implement JWT authentication
Add role-based access control
Set up API key management
Advanced Features
Historical data analysis
Technical indicators
Sentiment analysis
Portfolio management
Monitoring & Logging
Add structured logging
Implement performance monitoring
Set up alerting systems
And thats it! Let me know what y'all think and if you have any questions!
Top comments (0)