We are going to build a lightweight financial forecasting agent that pulls recent market data and generates a structured forward-looking analysis. It is useful for analysts who want to automate daily commentary on a watchlist without managing token-cost surprises on long context windows. We will run everything against Oxlo.ai so that pricing stays predictable regardless of how much historical data we feed the model.
What you'll need
- Python 3.10 or newer
pip install openai yfinance pandas- An Oxlo.ai API key from https://portal.oxlo.ai
Step 1: Fetch historical price data
I use yfinance to grab the last 90 days of OHLCV data and format the most recent 20 sessions as a CSV string. Keeping the context compact but informative gives the model enough signal without adding noise.
import yfinance as yf
import pandas as pd
def get_recent_data(ticker: str, days: int = 90) -> str:
stock = yf.Ticker(ticker)
df = stock.history(period=f"{days}d")
df = df.reset_index()[["Date", "Open", "High", "Low", "Close", "Volume"]]
df["Date"] = df["Date"].dt.strftime("%Y-%m-%d")
return df.tail(20).to_csv(index=False)
print(get_recent_data("AAPL"))
Step 2: Define the analyst system prompt
The system prompt locks the model into a JSON-only response and sets conservative expectations. This makes downstream parsing trivial and reduces hallucination.
SYSTEM_PROMPT = """You are a senior equity research analyst.
The user will provide recent OHLCV data for a single stock.
Write a concise forecast covering the next 5 trading days.
Respond ONLY with a JSON object containing these keys:
- ticker: string
- summary: string (2 sentences on recent price action)
- forecast_next_week: object with keys low, high (floats)
- reasoning: string (1 paragraph on technical or fundamental factors)
- risk_factors: list of strings (2 to 4 factors)
Be conservative. Do not hallucinate data outside the provided history."""
Step 3: Query Oxlo.ai and parse the forecast
Now we send the CSV data to Oxlo.ai. I use llama-3.3-70b because it handles structured instructions reliably, and because Oxlo.ai uses flat per-request pricing I do not need to worry about the exact row count.
import json
from openai import OpenAI
client = OpenAI(base_url="https://api.oxlo.ai/v1", api_key="YOUR_OXLO_API_KEY")
def analyze_ticker(ticker: str) -> dict:
data_csv = get_recent_data(ticker)
user_message = f"Ticker: {ticker}\nRecent data:\n{data_csv}"
response = client.chat.completions.create(
model="llama-3.3-70b",
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": user_message},
],
)
raw = response.choices[0].message.content
cleaned = raw.replace("
```json", "").replace("```
", "").strip()
return json.loads(cleaned)
result = analyze_ticker("AAPL")
print(json.dumps(result, indent=2))
Step 4: Package the logic into a reusable agent
Wrapping the fetch and inference steps in a class makes it easy to drop this into a larger pipeline or scheduler.
class FinancialForecastAgent:
def __init__(self, api_key: str, model: str = "llama-3.3-70b"):
self.client = OpenAI(base_url="https://api.oxlo.ai/v1", api_key=api_key)
self.model = model
def fetch(self, ticker: str) -> str:
stock = yf.Ticker(ticker)
df = stock.history(period="90d")
df = df.reset_index()[["Date", "Open", "High", "Low", "Close", "Volume"]]
df["Date"] = df["Date"].dt.strftime("%Y-%m-%d")
return df.tail(20).to_csv(index=False)
def forecast(self, ticker: str) -> dict:
data = self.fetch(ticker)
user_message = f"Ticker: {ticker}\nRecent data:\n{data}"
resp = self.client.chat.completions.create(
model=self.model,
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": user_message},
],
)
raw = resp.choices[0].message.content
cleaned = raw.replace("
```json", "").replace("```
", "").strip()
return json.loads(cleaned)
Run it
Instantiate the agent with your Oxlo.ai key and request a forecast.
agent = FinancialForecastAgent(api_key="YOUR_OXLO_API_KEY")
forecast = agent.forecast("AAPL")
print(json.dumps(forecast, indent=2))
Example output:
{
"ticker": "AAPL",
"summary": "AAPL has traded in a tight range over the last four weeks, with volume declining as the price approaches prior resistance near $230.",
"forecast_next_week": {
"low": 223.5,
"high": 231.0
},
"reasoning": "The 20-day moving average is flattening, suggesting consolidation. Momentum remains neutral, and without a catalyst the stock is likely to stay range-bound.",
"risk_factors": [
"Unexpected Fed commentary",
"Semiconductor supply chain disruptions",
"Broad market volatility"
]
}
Wrap-up and next steps
Two concrete ways to extend this:
- Schedule the script in a GitHub Action or cron job to run before market open and publish the JSON to Slack or email.
- Expand the agent to analyze a basket of stocks in a single prompt. Because Oxlo.ai charges a flat rate per request, not per token, you can pass a full sector watchlist with 90 days of data for each ticker and still pay the same price as a one-line greeting. See https://oxlo.ai/pricing for plan details.
Top comments (0)