<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Tanmay Kaper</title>
    <description>The latest articles on DEV Community by Tanmay Kaper (@tanmaykaper).</description>
    <link>https://dev.to/tanmaykaper</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4061773%2F73ca74fd-dce1-47f2-b43a-453fa8824bf3.png</url>
      <title>DEV Community: Tanmay Kaper</title>
      <link>https://dev.to/tanmaykaper</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tanmaykaper"/>
    <language>en</language>
    <item>
      <title>Why Generic Sentiment Analysis Doesn't Work for Trading — and What I Built Instead</title>
      <dc:creator>Tanmay Kaper</dc:creator>
      <pubDate>Tue, 04 Aug 2026 06:00:18 +0000</pubDate>
      <link>https://dev.to/tanmaykaper/why-generic-sentiment-analysis-doesnt-work-for-trading-and-what-i-built-instead-2n2c</link>
      <guid>https://dev.to/tanmaykaper/why-generic-sentiment-analysis-doesnt-work-for-trading-and-what-i-built-instead-2n2c</guid>
      <description>&lt;p&gt;I've been building an automated swing-trading system for NSE stocks — paper trading only, running&lt;br&gt;
daily on GitHub Actions. A few weeks ago I decided to add a news sentiment layer, and my first&lt;br&gt;
instinct was to reach for an off-the-shelf tool like VADER or TextBlob. I'm glad I didn't.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The problem with generic sentiment lexicons in finance&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In 2011, Loughran and McDonald published a paper in the Journal of Finance that's since become&lt;br&gt;
foundational in financial NLP. They took the Harvard-IV General Inquirer — a standard,&lt;br&gt;
widely-used sentiment dictionary at the time — and checked how well its "negative" word list&lt;br&gt;
actually held up against real 10-K filings.&lt;/p&gt;

&lt;p&gt;About three-quarters of the words it flagged as negative weren't negative at all in a financial&lt;br&gt;
context. Words like "liability," "tax," "cost," "capital," even "president" (as in "vice&lt;br&gt;
president") read as bad news in everyday English and are completely routine vocabulary in&lt;br&gt;
business writing. A generic model scoring financial headlines is, in a very literal sense,&lt;br&gt;
scoring the wrong language.&lt;/p&gt;

&lt;p&gt;So instead of importing a library, I built a small sentiment engine from the ground up, following&lt;br&gt;
the LM methodology: separate word categories for Negative, Positive, Uncertainty, and — the one&lt;br&gt;
that turned out to matter most — Litigious.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Two free sources, on purpose&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Headlines come from two independent free sources: Yahoo Finance's news feed (via &lt;code&gt;yfinance&lt;/code&gt;) and&lt;br&gt;
Google News RSS. No API keys, no paid tier. Two sources isn't redundancy for its own sake — I'd&lt;br&gt;
already been burned once elsewhere in this project by depending on a single free data source that&lt;br&gt;
silently changed its response shape. If one schema shifts without notice, the other source still&lt;br&gt;
covers you.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The negation bug that taught me the most&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Early testing threw a sentence at the scorer that should obviously read negative:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Quarterly results were not impressive, margins weak."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It came back &lt;em&gt;positive&lt;/em&gt;. The bug: my negation check looked backward a few words from any&lt;br&gt;
sentiment-bearing term to see if a negator preceded it. "Not" was technically within that window&lt;br&gt;
of "weak" — it just belonged to a &lt;em&gt;different clause&lt;/em&gt;, negating "impressive," not "weak" at all.&lt;br&gt;
The fix was scoping negation to stop at clause boundaries (commas, "but," "however") instead of&lt;br&gt;
just counting tokens. A small thing, but it's exactly the kind of bug that looks fine on&lt;br&gt;
obviously-easy test sentences and quietly wrecks real headlines.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why one dramatic headline shouldn't move the needle&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A single very negative headline about a stock with otherwise thin news coverage gets&lt;br&gt;
&lt;strong&gt;shrunk toward neutral&lt;/strong&gt; before it's trusted — the same statistical device (empirical-Bayes&lt;br&gt;
shrinkage toward a prior) used elsewhere in the project to stop a small sample of trades from&lt;br&gt;
over-swinging a pattern's calibrated weight. A cluster of five corroborating headlines gets&lt;br&gt;
trusted much more than one. Headlines also decay in relevance — today's news outweighs a&lt;br&gt;
five-day-old story, on an exponential half-life, so stale coverage doesn't linger in the score&lt;br&gt;
forever.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Two different jobs, kept separate&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The sentiment score does two things, and I deliberately didn't collapse them into one number:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;soft factor&lt;/strong&gt; — a small (10%-weighted) input into a larger cross-sectional conviction score
that also includes momentum, trend quality, volume, and relative strength. Mildly positive news
nudges conviction up a little. It's a weak, noisy signal next to price/volume factors with
decades of published evidence behind them, and it's sized accordingly.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;hard veto&lt;/strong&gt; — an independent, absolute-threshold check that can block a trade outright on a
fresh, corroborated cluster of litigious/fraud-flagged headlines, regardless of how good
everything else looks. This is the asymmetric case a pure price-based system is structurally
blind to until the news is already priced into the chart.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Where this fits into the bigger picture&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The sentiment engine is one of five layers a trade candidate has to clear: a technical pattern&lt;br&gt;
scanner, a fundamental soft-gate, a cross-sectional alpha score, this sentiment layer, and a&lt;br&gt;
multi-tier risk manager (portfolio risk budget, sector concentration caps, a drawdown circuit&lt;br&gt;
breaker). Every layer can be independently toggled on or off, specifically so I can A/B test&lt;br&gt;
whether each one is actually contributing anything, instead of just trusting that a&lt;br&gt;
sophisticated-sounding feature is a helpful one.&lt;/p&gt;

&lt;p&gt;I'm not going to claim this makes money — the live paper-trading sample is still small, and I'd&lt;br&gt;
rather build the validation tooling properly than dress up a handful of trades as a track record.&lt;br&gt;
That's genuinely the more interesting engineering problem anyway: not "does this sound smart," but&lt;br&gt;
"how do I actually find out."&lt;/p&gt;

&lt;p&gt;Repo (fully open, MIT licensed): &lt;a href="https://github.com/tanmaykaper/Paper-Trading-Bot" rel="noopener noreferrer"&gt;https://github.com/tanmaykaper/Paper-Trading-Bot&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Would genuinely welcome pushback on the lexicon design or the shrinkage constants — still tuning&lt;br&gt;
both.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>automation</category>
      <category>nlp</category>
    </item>
  </channel>
</rss>
