CausalPulse: Our Story

Inspiration

Financial headlines are everywhere, but most of them are noisy and repetitive. "Fed raises rates." "Oil prices spike." "Tech stocks slide." A human analyst reading these instinctively connects the dots. A rate hike tends to pressure growth stocks. An oil spike tends to squeeze airline margins. But that kind of pattern recognition comes from experience. It's not something any single headline carries on its own.

I kept coming back to one question. What if an agent could build that same kind of experience, but computationally? Not just summarizing today's news, but actually remembering how similar events played out before, and using that memory to say something useful about what happens next. That's where CausalPulse came from. An agent that treats financial news as one long chain of cause and effect, and keeps learning to read it a little better over time.

What it does

CausalPulse reads live financial headlines, uses Qwen to pull out the causal relationship each one implies (cause leads to effect), and stores that in a persistent, deduplicated memory bank. When a new headline shows up, it gets checked against everything the agent has already learned. If there's a confident match, CausalPulse fires a prediction with a confidence score and a time window, then later checks the live web to see if it actually panned out. Over time that builds a real track record instead of a pile of one-off guesses.

How I built it

The backend is FastAPI and SQLite, with APScheduler running an ingest cycle every two hours. Headline extraction and later verification both go through Qwen, via Alibaba's Dashscope endpoint.

For memory, I didn't want exact text matching. Two headlines can describe the exact same causal pattern in completely different words, so causal pairs are deduplicated using sentence transformer cosine similarity instead. That way a paraphrased version of something the agent already knows reinforces the existing pattern instead of cluttering up the memory bank with near duplicates.

The frontend is a single HTML file, vanilla JS and D3.js, no build step and no framework overhead. There's a force directed graph for the Memory Bank, animated chain visualizations for individual predictions, and a chat interface grounded in the agent's own stored knowledge instead of just answering from general training.

Once the core loop worked locally, I bootstrapped the memory bank with 50,000 historical financial headlines so it would have a real foundation of learned patterns before going live on Alibaba Cloud.

Challenges I ran into

The silent bug that took forever to find. My headline counter sat at zero for days, even though the rest of the pipeline was clearly working. Headlines were being fetched, filtered, extracted, turned into predictions. It turned out fetch_headlines() was returning the data but never actually writing it to the headlines table. Nothing crashed. Nothing errored. It just quietly did less than it looked like it was doing, which honestly is a lot harder to catch than something that throws a loud error.

A parameter that looked right but did nothing. While chasing down a "why does the live feed keep showing the same headline" problem, I found out Tavily's days recency filter only actually works when it's paired with topic="news". I had it set to topic="finance", so the recency filter had been silently ignored the whole time. It wasn't caching. It wasn't a rate limit. It wasn't Tavily being down. The code had just been searching an evergreen, quote page heavy category with no working freshness filter at all, and I only caught it by writing a small script to print exactly what Tavily was returning under the hood.

Deploying to the cloud for the first time, ever. This was genuinely my first time deploying anything to a cloud server. I hit "permission denied (publickey)" errors that made no sense, until I found a buried PasswordAuthentication no line in /etc/ssh/sshd_config quietly overriding a setting I thought I'd already changed. I also had the very real realization, live, that closing my browser tab shouldn't take down a running app, which is what finally pushed me to learn systemd instead of just running python main.py and hoping nothing broke.

A feature that looked smart but produced nonsense. Early on, vague headlines like "Crude Oil (CL=F) - Yahoo Finance" were slipping past my relevance filters and matching known patterns closely enough to fire genuinely bogus predictions. One literally read "Crude Oil leads to gold price retreats," which meant nothing at all. I ended up building extra filters just for ticker symbol pages and listicle style headlines that were technically keyword rich but described no real event.

Accomplishments that I'm proud of

Getting the semantic memory system to actually feel like memory, reinforcing confidence on a pattern it's seen many times instead of treating every headline like a blank slate, is the part I'm most proud of. It's the difference between a chatbot that summarizes the news and an agent that's actually building understanding over time.

I'm also proud of shipping the whole loop end to end as a solo builder. Ingestion, extraction, memory, prediction, and verification, deployed live and reachable by anyone, not just sitting on my laptop.

What I learned

Bugs that produce no error at all are more dangerous than the loud ones. They hide in plain sight because everything downstream still looks fine. I learned to build small diagnostic scripts that print raw, unfiltered output whenever something felt slightly off, instead of just trusting that a quiet run meant correct behavior.

I also learned that reusing infrastructure you already trust beats adding a new dependency for a narrow reason. Swapping from NewsAPI to Tavily, which I was already using elsewhere in the project, turned out to be the right call the moment I hit NewsAPI's localhost restriction on deployment. One less key to manage, one less thing to break.

What's next for CausalPulse

Tightening the prediction verification window logic, expanding beyond a single search query to cover more market sectors without bringing back the noise that broader queries caused early on, and seeing whether this same causal memory approach holds up outside financial news too.

Built With

  • alibabacloud
  • fastapi
  • newsapi
  • python
  • qwen
  • tavily
Share this project:

Updates