Stock Analysis - Built with AI Assistance
8 Jan 2024 · 6 min read
- AI-Assisted
- Finance
- Python
- Data Analysis
Overview
Stock Analysis is a comprehensive tool for tracking stocks, analyzing price movements, and generating trading insights. It includes price tracking, technical indicators, portfolio management, and performance visualization. Built with AI pair programming assistance.
The Goal
Create a stock analysis tool that provides:
- Real-time and historical price data
- Technical analysis indicators (moving averages, RSI, MACD)
- Portfolio tracking and performance metrics
- Visual charts and insights
- Alert system for price movements
AI Tools Used
- Claude Code: Financial calculations, API integration, data visualization
- Qwen: Pandas optimization, statistical analysis, chart styling
How AI Helped
API Integration
Stock Data Fetcher
Claude helped implement robust API handling:
import requests
from typing import Optional, List, Dict
from datetime import datetime, timedelta
import pandas as pd
class StockDataFetcher:
def __init__(self, api_key: str):
self.api_key = api_key
self.base_url = "https://api.alpaca.markets/v2"
self.headers = {
"APCA-API-KEY-ID": api_key,
"APCA-API-SECRET-KEY": api_key
}
def get_historical_data(
self,
symbol: str,
start_date: datetime,
end_date: datetime,
timeframe: str = "1Day"
) -> pd.DataFrame:
"""Fetch historical stock data."""
params = {
"timeframe": timeframe,
"start": start_date.isoformat(),
"end": end_date.isoformat()
}
response = requests.get(
f"{self.base_url}/stocks/{symbol}/bars",
headers=self.headers,
params=params
)
response.raise_for_status()
bars = response.json()["bars"]
df = pd.DataFrame(bars)
df["timestamp"] = pd.to_datetime(df["t"])
df.set_index("timestamp", inplace=True)
return df[["open", "high", "low", "close", "volume"]]
def get_current_price(self, symbol: str) -> Optional[float]:
"""Get current stock price."""
params = {"timeframe": "1Min"}
response = requests.get(
f"{self.base_url}/stocks/{symbol}/bars",
headers=self.headers,
params=params
)
if response.status_code == 200:
bars = response.json()["bars"]
if bars:
return bars[-1]["c"]
return None
def get_multiple_stocks(
self,
symbols: List[str],
start_date: datetime,
end_date: datetime
) -> Dict[str, pd.DataFrame]:
"""Fetch data for multiple stocks."""
data = {}
for symbol in symbols:
try:
data[symbol] = self.get_historical_data(symbol, start_date, end_date)
except Exception as e:
print(f"Error fetching {symbol}: {e}")
return data
Technical Indicators
Indicator Calculations
AI generated technical analysis functions:
import numpy as np
class TechnicalAnalyzer:
@staticmethod
def calculate_sma(prices: pd.Series, window: int) -> pd.Series:
"""Calculate Simple Moving Average."""
return prices.rolling(window=window).mean()
@staticmethod
def calculate_ema(prices: pd.Series, window: int) -> pd.Series:
"""Calculate Exponential Moving Average."""
return prices.ewm(span=window, adjust=False).mean()
@staticmethod
def calculate_rsi(prices: pd.Series, window: int = 14) -> pd.Series:
"""Calculate Relative Strength Index."""
delta = prices.diff()
gain = (delta.where(delta > 0, 0)).rolling(window=window).mean()
loss = (-delta.where(delta < 0, 0)).rolling(window=window).mean()
rs = gain / loss
rsi = 100 - (100 / (1 + rs))
return rsi
@staticmethod
def calculate_macd(prices: pd.Series) -> pd.DataFrame:
"""Calculate MACD indicator."""
ema_12 = prices.ewm(span=12, adjust=False).mean()
ema_26 = prices.ewm(span=26, adjust=False).mean()
macd_line = ema_12 - ema_26
signal_line = macd_line.ewm(span=9, adjust=False).mean()
histogram = macd_line - signal_line
return pd.DataFrame({
"macd": macd_line,
"signal": signal_line,
"histogram": histogram
})
@staticmethod
def calculate_bollinger_bands(
prices: pd.Series,
window: int = 20,
num_std: float = 2.0
) -> pd.DataFrame:
"""Calculate Bollinger Bands."""
sma = prices.rolling(window=window).mean()
std = prices.rolling(window=window).std()
upper_band = sma + (std * num_std)
lower_band = sma - (std * num_std)
return pd.DataFrame({
"upper": upper_band,
"middle": sma,
"lower": lower_band
})
@staticmethod
def calculate_volatility(prices: pd.Series, window: int = 20) -> pd.Series:
"""Calculate rolling volatility (standard deviation of returns)."""
returns = prices.pct_change()
return returns.rolling(window=window).std() * np.sqrt(252) # Annualized
Portfolio Management
Portfolio Tracker
AI designed a comprehensive portfolio tracking system:
from dataclasses import dataclass, field
from typing import Dict, List, Optional
from datetime import datetime
@dataclass
class Holding:
symbol: str
shares: float
avg_cost: float
purchase_date: datetime = field(default_factory=datetime.now)
@property
def total_cost(self) -> float:
return self.shares * self.avg_cost
@dataclass
class Portfolio:
holdings: Dict[str, Holding] = field(default_factory=dict)
cash: float = 100000.0
def add_position(self, symbol: str, shares: float, price: float):
"""Add or increase a position."""
if symbol in self.holdings:
existing = self.holdings[symbol]
total_shares = existing.shares + shares
total_cost = existing.total_cost + (shares * price)
new_avg_cost = total_cost / total_shares
self.holdings[symbol] = Holding(
symbol=symbol,
shares=total_shares,
avg_cost=new_avg_cost,
purchase_date=existing.purchase_date
)
else:
self.holdings[symbol] = Holding(
symbol=symbol,
shares=shares,
avg_cost=price
)
self.cash -= shares * price
def remove_position(self, symbol: str, shares: float, price: float) -> float:
"""Sell shares and return proceeds."""
if symbol not in self.holdings:
raise ValueError(f"No position in {symbol}")
holding = self.holdings[symbol]
if shares > holding.shares:
raise ValueError(f"Cannot sell more than owned: {holding.shares}")
proceeds = shares * price
self.cash += proceeds
if shares == holding.shares:
del self.holdings[symbol]
else:
holding.shares -= shares
return proceeds
def get_total_value(self, current_prices: Dict[str, float]) -> float:
"""Calculate total portfolio value."""
stock_value = sum(
holding.shares * current_prices.get(holding.symbol, 0)
for holding in self.holdings.values()
)
return self.cash + stock_value
def get_performance(self, current_prices: Dict[str, float]) -> List[Dict]:
"""Get performance for each holding."""
performance = []
for symbol, holding in self.holdings.items():
current_price = current_prices.get(symbol, 0)
current_value = holding.shares * current_price
gain_loss = current_value - holding.total_cost
gain_loss_pct = (gain_loss / holding.total_cost) * 100
performance.append({
"symbol": symbol,
"shares": holding.shares,
"avg_cost": holding.avg_cost,
"current_price": current_price,
"current_value": current_value,
"gain_loss": gain_loss,
"gain_loss_pct": gain_loss_pct
})
return performance
Data Visualization
Chart Generator
AI helped create comprehensive visualizations:
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
class StockChartGenerator:
def __init__(self, style: str = "dark"):
self.style = style
self.colors = {
"dark": {
"background": "#0f172a",
"grid": "#334155",
"text": "#e2e8f0",
"up": "#22c55e",
"down": "#ef4444"
},
"light": {
"background": "#ffffff",
"grid": "#e5e7eb",
"text": "#1f2937",
"up": "#16a34a",
"down": "#dc2626"
}
}
def create_price_chart(
self,
df: pd.DataFrame,
symbol: str,
show_ma: bool = True,
show_volume: bool = True
) -> plt.Figure:
"""Create a comprehensive price chart with indicators."""
fig, axes = plt.subplots(2, 1, figsize=(14, 8), gridspec_kw={'height_ratios': [3, 1]})
colors = self.colors[self.style]
# Price chart
ax1 = axes[0]
ax1.plot(df.index, df["close"], color=colors["up"], linewidth=1.5, label="Price")
if show_ma:
sma_20 = TechnicalAnalyzer.calculate_sma(df["close"], 20)
sma_50 = TechnicalAnalyzer.calculate_sma(df["close"], 50)
ax1.plot(sma_20.index, sma_20, "w--", linewidth=1, label="SMA 20")
ax1.plot(sma_50.index, sma_50, "w--", linewidth=1, label="SMA 50")
ax1.set_title(f"{symbol} Price History", fontsize=14, color=colors["text"])
ax1.set_ylabel("Price", color=colors["text"])
ax1.grid(True, alpha=0.3, color=colors["grid"])
ax1.legend(loc="upper left")
# Volume chart
if show_volume:
ax2 = axes[1]
colors_volume = [colors["up"] if df["close"].iloc[i] >= df["open"].iloc[i]
else colors["down"] for i in range(len(df))]
ax2.bar(df.index, df["volume"], color=colors_volume, alpha=0.5)
ax2.set_ylabel("Volume", color=colors["text"])
ax2.grid(True, alpha=0.3, color=colors["grid"])
# Formatting
ax1.xaxis.set_major_formatter(mdates.DateFormatter("%Y-%m-%d"))
plt.xticks(rotation=45)
plt.tight_layout()
return fig
The Process
Prompting Strategy
Effective approach:
- Define data models (Holding, Portfolio)
- Implement API layer
- Add technical indicators
- Build portfolio management
- Create visualizations
Example prompt:
I need a Python class for tracking stock portfolio.
It should:
1. Track holdings with symbol, shares, and average cost
2. Allow adding and removing positions
3. Calculate current value and gains/losses
4. Support multiple stocks
Start with the dataclass definitions.
Human Decisions
- Which indicators to include
- Alert thresholds
- Portfolio allocation strategy
- Risk management rules
Iteration Cycle
- Define data structure
- Generate API integration
- Add calculations
- Test with real data
- Build visualization
Challenges
What AI Couldn't Help With
- Market prediction: AI cannot predict stock movements
- Regulatory compliance: Legal requirements need human review
- Risk assessment: Investment decisions require human judgment
Unexpected Issues
- API rate limits
- Data gaps in historical data
- Stock splits and adjustments
Results
Quantitative
- Development time: 4 days with AI vs estimated 6-8 days without
- Indicators: 10+ technical indicators implemented
- Data support: Works with major stock exchanges
Qualitative
- Clean, modular code structure
- Well-documented calculations
- Extensible architecture
Key Learnings
- AI excels at calculations - Technical indicators are well-defined
- Modular design helps - Separate API, calculations, and visualization
- Testing is crucial - Validate calculations against known values
- Error handling matters - API calls can fail
- Documentation is key - Explain financial concepts clearly
Code Samples
Example Prompt
I need to calculate RSI (Relative Strength Index) for stock analysis.
Use pandas for efficiency.
Include proper handling of the first 14 periods where RSI is undefined.
Resulting Code
def calculate_rsi(prices: pd.Series, window: int = 14) -> pd.Series:
"""Calculate Relative Strength Index."""
delta = prices.diff()
# Separate gains and losses
gain = delta.where(delta > 0, 0)
loss = (-delta).where(delta < 0, 0)
# Calculate average gain and loss
avg_gain = gain.rolling(window=window).mean()
avg_loss = loss.rolling(window=window).mean()
# Calculate RS and RSI
rs = avg_gain / avg_loss
rsi = 100 - (100 / (1 + rs))
return rsi
Next Steps
- Add real-time alerts
- Integrate with trading platforms
- Add fundamental analysis
- Create mobile app
This project was built with AI pair programming assistance using Claude Code and Qwen.