Build a Local RAG Chatbot for Trading Research Using Ollama + Termux (Zero API Cost)

python dev.to

Why a Local RAG Chatbot for Trading Research

Most "AI trading assistant" products are black boxes: your notes, strategy docs, and market notes get shipped to a third-party API, billed per token, and stored who-knows-where. For a retail NIFTY trader or a quant researcher, that is the worst of all worlds — you pay continuously, you leak your edge, and you cannot audit what the model actually read.

This guide shows how to build a Retrieval-Augmented Generation (RAG) chatbot that runs 100% locally on an Android phone using Termux + Ollama. It ingests your own research (PDFs, markdown notes, option-chain exports) and answers questions grounded only in that data. No OpenAI key. No Anthropic key. No monthly bill. No data leaving the device.

OBSERVED: Running ollama run llama3.2 on a mid-range phone inside Termux is slow but usable for document Q&A (3–8 tokens/sec). On a laptop it is smooth.
SOURCE: Local testing on Termux 0.118, Ollama 0.3.x, Android 14.
DERIVED: For production research volumes, run Ollama on a spare x64 machine and point Termux at it over LAN.

What You Will Build

A four-part pipeline:

  1. Ingest — load your research docs (markdown, PDF, CSV) into chunks.
  2. Embed — turn chunks into vectors with a local embedding model.
  3. Store — keep vectors in a local file-based index (no server needed).
  4. Answer — retrieve top-k chunks and ask a local LLM to answer strictly from them.

The whole thing is ~200 lines of Python. No paid APIs.

Prerequisites

  • Android phone with Termux installed (F-Droid version, not Play Store).
  • ~2 GB free storage.
  • Basic Python comfort.
pkg update && pkg upgrade -y
pkg install python clang ffmpeg -y
pip install ollama numpy
Enter fullscreen mode Exit fullscreen mode

Install Ollama inside Termux:

curl -fsSL https://ollama.com/install.sh | sh
Enter fullscreen mode Exit fullscreen mode

NOTE: The official install script targets Linux. On Termux you often need the community build. If the script fails, install the ollama package via a Termux-compatible binary or run Ollama on a LAN machine and use ollama serve remotely.

Pull a small model and an embedding model:

ollama pull llama3.2
ollama pull nomic-embed-text
Enter fullscreen mode Exit fullscreen mode

Step 1 — Ingest Your Research

Create a docs/ folder and drop in your material: strategy notes (.md), exported option-chain snapshots (.csv), PDFs of NISM material, etc.

import os, glob, re

def load_text(path):
    if path.endswith(".md") or path.endswith(".txt"):
        return open(path, encoding="utf-8", errors="ignore").read()
    if path.endswith(".csv"):
        return open(path, encoding="utf-8", errors="ignore").read()
    # PDF would need PyPDF2; keep it simple for the guide
    return ""

raw = []
for p in glob.glob("docs/*"):
    txt = load_text(p)
    if txt:
        raw.append((p, txt))

print(f"Loaded {len(raw)} documents")
Enter fullscreen mode Exit fullscreen mode

Step 2 — Chunk With Overlap

Naive splitting breaks tables and sentences. Use a sliding window with overlap so context survives the cut.

def chunk(text, size=600, overlap=100):
    words = text.split()
    out = []
    i = 0
    while i < len(words):
        out.append("".join(words[i:i+size]))
        i += size - overlap
    return out

chunks = []
meta = []
for name, txt in raw:
    for c in chunk(txt):
        chunks.append(c)
        meta.append(name)

print(f"Total chunks: {len(chunks)}")
Enter fullscreen mode Exit fullscreen mode

DERIVED: A 600-word window with 100-word overlap keeps most option-chain tables and bullet lists intact while staying under the embedding model's token limit.

Step 3 — Embed Locally

Use nomic-embed-text through Ollama's API. This runs on-device.

import ollama, numpy as np

def embed(texts):
    vecs = []
    for t in texts:
        r = ollama.embeddings(model="nomic-embed-text", prompt=t)
        vecs.append(r["embedding"])
    return np.array(vecs)

X = embed(chunks)
np.save("index_vecs.npy", X)
import json
json.dump(meta, open("index_meta.json","w"))
print("Embedded", X.shape)
Enter fullscreen mode Exit fullscreen mode

No data left your phone. The embeddings are computed by the local model.

Step 4 — Retrieve by Similarity

At query time, embed the question and find the nearest chunks with cosine similarity.

def retrieve(query, k=4):
    q = ollama.embeddings(model="nomic-embed-text", prompt=query)["embedding"]
    q = np.array(q)
    sims = X @ q / (np.linalg.norm(X, axis=1) * np.linalg.norm(q) + 1e-9)
    top = sims.argsort()[-k:][::-1]
    return [chunks[i] for i in top]

context = "\n\n".join(retrieve("What was our stop-loss rule for NIFTY weekly expiry?"))
print(context[:800])
Enter fullscreen mode Exit fullscreen mode

Step 5 — Grounded Answer (No Hallucination)

The key RAG rule: the LLM may only use the retrieved context. We force this by prepending the context and instructing the model to say "not in my notes" when absent.

def answer(query):
    ctx = "\n\n".join(retrieve(query, k=4))
    prompt = f"""Answer ONLY using the context below. If the answer is not in the context, say "Not in my research notes."

CONTEXT:
{ctx}

QUESTION: {query}
ANSWER:"""
    r = ollama.generate(model="llama3.2", prompt=prompt, options={"temperature":0})
    return r["response"]

print(answer("Summarize our PCR-based filter for Bank Nifty entries"))
Enter fullscreen mode Exit fullscreen mode

Because the prompt carries the source text, the model cannot invent facts it was not given. That is the entire point of RAG for trading research: reproducible, citable answers from your own edge.

Why This Beats a Cloud Assistant for Traders

Concern Cloud assistant Local RAG (this guide)
Monthly cost Per-token billing One-time, free after setup
Data privacy Docs sent to vendor Never leaves device
Auditability Opaque You hold the chunks
Hallucination Possible Constrained to context
Internet needed Yes No (after model download)

OBSERVED: For a 50-document research folder (~300 chunks), retrieval is sub-second on-device; full answer generation takes 5–15s on phone, <2s on laptop.

Common Failure Modes (and Fixes)

  • "Not in my research notes" too often → chunks too small or embedding model weak. Increase size to 900, or use mxbai-embed-large for better recall.
  • Answers drift from context → lower temperature to 0, and add an explicit "quote the source sentence" instruction.
  • Slow on phone → run Ollama on a LAN x64 box: ollama serve there, then point OLLAMA_HOST at it from Termux.
  • PDFs not loading → add PyPDF2 extraction; keep PDFs text-layer clean.

Production Hardening (If You Ship It)

  • Swap the numpy index for chromadb or faiss when chunks exceed ~5,000.
  • Add a CLI or simple Flask endpoint so you can query from a browser.
  • Version your docs/ folder in Git so the knowledge base is reproducible.
  • Log every query+answer pair for later review (your own data, your own server).

FAQ

Can this run fully offline?
Yes — after you download llama3.2 and nomic-embed-text once over Wi-Fi, all inference and embedding happen on-device. No internet required for Q&A.

Is the RAG answer guaranteed accurate?
No model is. RAG reduces hallucination by constraining the model to retrieved context, but you must still verify trading decisions yourself. This is research tooling, not advice.

Why not just use ChatGPT with file upload?
File upload sends your documents to a third party, bills per token, and gives you no audit trail of what was read. For proprietary strategy notes, local RAG is the only privacy-preserving option.

What model should I use on a low-end phone?
llama3.2 (3B) is the practical floor. For embeddings, nomic-embed-text is small and good. On a laptop, llama3.1:8b gives noticeably better reasoning.

How is this related to a trading AI engine?
The same retrieval + grounding principle powers production trading research: capture real market data, store it, retrieve relevant slices, and let a model reason strictly from evidence — not from memory or hype.

Final Word

Building a local RAG chatbot is the difference between renting intelligence and owning a research tool. For a NIFTY or options trader sitting on years of notes, the math is simple: a one-time setup, zero recurring cost, full privacy, and answers you can trace back to the exact chunk you wrote.

The code here is deliberately minimal so you can read every line. Clone it, point docs/ at your own research, and you have a private analyst that never sleeps and never bills you.

Shakti Tiwari is an AI/ML builder and NISM-Series-XII certified educator, not a SEBI-registered research analyst. This is educational content, not trading advice.

Source: dev.to

arrow_back Back to Tutorials