Financial text is noisy. Earnings transcripts, SEC filings, and analyst reports contain signals that are easy to miss when you read them manually. In this guide we will build a small Python agent that ingests raw financial prose and returns structured JSON with sentiment, key metrics, and risk flags using Oxlo.ai.
What you'll need
- Python 3.10 or newer.
- An Oxlo.ai API key from https://portal.oxlo.ai.
- The OpenAI SDK:
pip install openai
Step 1: Set up the Oxlo.ai client
We will load the API key from the environment and instantiate the client. Oxlo.ai exposes an OpenAI-compatible endpoint, so the SDK works without changes.
import os
from openai import OpenAI
client = OpenAI(
base_url="https://api.oxlo.ai/v1",
api_key=os.environ.get("OXLO_API_KEY")
)
Step 2: Write the system prompt
The system prompt constrains the model to act as a financial analyst and return only valid JSON. I keep the schema lightweight so it works reliably across different model sizes.
SYSTEM_PROMPT = """You are a senior financial analyst.
Read the user-provided financial text and produce a strictly valid JSON object with these keys:
- "sentiment": one of ["bullish", "neutral", "bearish"]
- "key_metrics": an array of strings naming any quantitative metrics mentioned (e.g., revenue, EBITDA, EPS)
- "risks": an array of strings describing risks or headwinds mentioned
- "one_sentence_summary": a concise summary of the text's main takeaway
Rules:
- Output ONLY the JSON object. No markdown fences, no commentary.
- Use null for any field that cannot be filled.
"""
Step 3: Prepare sample financial text
I will use a short excerpt from a fictional earnings release so the script is self-contained and runnable. Replace this string with a real transcript or filing when you move to production.
TRANSCRIPT = """
Q3 2024 Earnings Highlights
Revenue grew 12% year-over-year to $1.2 billion, slightly below the $1.25 billion consensus.
Gross margin compressed 150 basis points to 58% due to higher input costs.
Management guided Q4 revenue between $1.15 billion and $1.2 billion, citing ongoing supply chain constraints in the semiconductor division.
Operating cash flow remained strong at $180 million, but capex is expected to rise next quarter.
"""
Step 4: Build the analysis function
This function wraps the Oxlo.ai chat completion call. I use llama-3.3-70b because it handles long-context financial documents reliably, and Oxlo.ai's request-based pricing means the cost stays flat even if you paste in a 10-K excerpt that would consume heavy input tokens on traditional token-based platforms.
import json
def analyze_financial_text(text: str) -> dict:
response = client.chat.completions.create(
model="llama-3.3-70b",
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": text},
],
)
raw = response.choices[0].message.content.strip()
# Some models may return a markdown code block, so strip fences if present.
if raw.startswith("
```"):
lines = raw.splitlines()
if lines[0].startswith("```
"):
lines = lines[1:]
if lines and lines[-1].startswith("
```
"):
lines = lines[:-1]
raw = "\n".join(lines).strip()
return json.loads(raw)
Run it
Now we can pass the transcript through the agent and print the results.
if __name__ == "__main__":
result = analyze_financial_text(TRANSCRIPT)
print(json.dumps(result, indent=2))
Example output:
{
"sentiment": "bearish",
"key_metrics": [
"revenue",
"gross margin",
"operating cash flow",
"capex"
],
"risks": [
"revenue below consensus",
"gross margin compression",
"supply chain constraints in semiconductor division",
"expected rise in capex"
],
"one_sentence_summary": "Q3 revenue missed consensus and margins compressed due to higher costs, while management issued cautious Q4 guidance citing semiconductor supply chain constraints."
}
Wrap-up and next steps
From here, you can extend the agent by adding a Pydantic model to validate the JSON schema before you store it. If you plan to process full 10-K filings or multi-page transcripts, swap in kimi-k2.6 or deepseek-v3.2 on Oxlo.ai and take advantage of the flat per-request pricing to keep long-context workloads predictable.
Top comments (0)