<?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: Stock Expert AI</title>
    <description>The latest articles on DEV Community by Stock Expert AI (@stockexpertai).</description>
    <link>https://dev.to/stockexpertai</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3771379%2F0fdbc45a-c3f2-4543-ad08-05961e3ef348.png</url>
      <title>DEV Community: Stock Expert AI</title>
      <link>https://dev.to/stockexpertai</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/stockexpertai"/>
    <language>en</language>
    <item>
      <title>Building a Daily Data Pipeline That Survives Market Holidays</title>
      <dc:creator>Stock Expert AI</dc:creator>
      <pubDate>Sun, 24 May 2026 23:15:37 +0000</pubDate>
      <link>https://dev.to/stockexpertai/building-a-daily-data-pipeline-that-survives-market-holidays-1jb</link>
      <guid>https://dev.to/stockexpertai/building-a-daily-data-pipeline-that-survives-market-holidays-1jb</guid>
      <description>&lt;p&gt;So, I had to build this data pipeline that grabs financial market data. Daily. Sounds simple, right?&lt;/p&gt;

&lt;p&gt;Not so fast. Market holidays threw a wrench in the works. The data source wouldn't update, and my pipeline couldn't just choke on those days. Pipeline failures are annoying.&lt;/p&gt;

&lt;p&gt;I needed the pipeline to either run smoothly, processing the data available (even if it was the same as yesterday), or skip the run entirely — no errors, no alerts.&lt;/p&gt;

&lt;p&gt;Here's the simple stupid strategy I landed on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Get a holiday calendar.&lt;/li&gt;
&lt;li&gt;  Check the date at the start.&lt;/li&gt;
&lt;li&gt;  Run or exit based on that check.&lt;/li&gt;
&lt;li&gt;  Log the decision.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's look at some Python code.&lt;/p&gt;

&lt;p&gt;First, the holiday calendar. Hardcoding? No thanks. I'm not into maintenance nightmares. Instead, I generate it with code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt;
&lt;span class="c1"&gt;# Assume 'market_holidays' is a function to generate a list of holidays
# based on the current year.
&lt;/span&gt;&lt;span class="n"&gt;holiday_list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;market_holidays&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;today&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;year&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, before the actual processing, check if today's a holiday:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;today&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;today&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;today&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;holiday_list&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Today is a market holiday. Skipping data processing.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# Optionally, log this decision to a file or database.
&lt;/span&gt;    &lt;span class="c1"&gt;# Here's a basic logging example:
&lt;/span&gt;    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pipeline_log.txt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;log_file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;log_file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;today&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: Skipped due to holiday&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  &lt;span class="c1"&gt;# Gracefully exit the script
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If it's not a holiday, the script just keeps going.&lt;/p&gt;

&lt;p&gt;But what about the next business day? How do we ensure the pipeline runs then and processes the data correctly? Initially, I let the scheduler handle it. It worked, assuming the scheduler retried on the next available day.&lt;/p&gt;

&lt;p&gt;But sometimes the data source &lt;em&gt;only&lt;/em&gt; provided data for trading days. That's when I added a "lookback" mechanism. If today's a holiday, check the previous business day.&lt;/p&gt;

&lt;p&gt;This meant tweaking the date checking:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timedelta&lt;/span&gt;

&lt;span class="n"&gt;today&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;today&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;data_date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;today&lt;/span&gt;  &lt;span class="c1"&gt;# Default to today
&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;today&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;holiday_list&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Today is a market holiday. Checking previous business day.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;data_date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;today&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nf"&gt;timedelta&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;days&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# Keep subtracting days until we find a non-holiday
&lt;/span&gt;    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;data_date&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;holiday_list&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;data_date&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="nf"&gt;timedelta&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;days&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Using data from &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;data_date&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# Log this decision
&lt;/span&gt;    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pipeline_log.txt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;log_file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;log_file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;today&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: Using data from &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;data_date&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; (holiday fallback)&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Now, fetch data using the 'data_date' variable
# data = fetch_market_data(data_date)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ensures the pipeline grabs data from the most recent trading day, even on holidays. This is obvious.&lt;/p&gt;

&lt;p&gt;A few more things to remember.&lt;/p&gt;

&lt;p&gt;Error handling is vital. What if the data source is down for other reasons? Add retry logic and logging, so you can diagnose issues quickly.&lt;/p&gt;

&lt;p&gt;And monitoring? Gotta track performance and spot anomalies. If the pipeline keeps skipping runs, that's a problem.&lt;/p&gt;

&lt;p&gt;Test everything. Simulate holidays to see if it behaves as expected.&lt;/p&gt;

&lt;p&gt;Building a robust data pipeline that can handle market holidays takes thought and planning. A holiday calendar, conditional execution, and a lookback mechanism? This is the way.&lt;/p&gt;

&lt;p&gt;Now I can sleep soundly, knowing my pipeline won't bother me on Christmas.&lt;/p&gt;

</description>
      <category>automation</category>
      <category>dataengineering</category>
      <category>python</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Building a Daily Data Pipeline That Survives Market Holidays</title>
      <dc:creator>Stock Expert AI</dc:creator>
      <pubDate>Sun, 24 May 2026 21:52:58 +0000</pubDate>
      <link>https://dev.to/stockexpertai/building-a-daily-data-pipeline-that-survives-market-holidays-12cn</link>
      <guid>https://dev.to/stockexpertai/building-a-daily-data-pipeline-that-survives-market-holidays-12cn</guid>
      <description>&lt;p&gt;I recently put together a daily data pipeline to pull and process financial data. Simple stupid, right? Grab data, clean it, load it.&lt;/p&gt;

&lt;p&gt;Of course, the devil's in the details. And one of the biggest headaches? Market holidays.&lt;/p&gt;

&lt;p&gt;The pipeline needed to run &lt;em&gt;daily&lt;/em&gt;, grabbing data from the prior day's trading. Weekdays are easy. Weekends? Obvious. But what about holidays when the markets are closed? If the pipeline blindly tries to grab data for a non-trading day, it errors out. The whole thing grinds to a halt. Nobody wants that.&lt;/p&gt;

&lt;p&gt;Here's how I tackled this, focusing on making the pipeline solid and avoiding those failures.&lt;/p&gt;

&lt;p&gt;First, I needed a way to determine if a given date was a market holiday. Hardcoding a list? Brittle. Constant updating? No thanks. Instead, I decided to calculate market holidays dynamically.&lt;/p&gt;

&lt;p&gt;There are ways to do this, depending on the markets you care about. I wrote a function that checks if a given date is a business day. If it isn't, it flags it as a holiday.&lt;/p&gt;

&lt;p&gt;The core of this function? Checking the day of the week (weekends are &lt;em&gt;obviously&lt;/em&gt; holidays) and then iterating through a list of known holidays for the current year. This list is built based on the country and market.&lt;/p&gt;

&lt;p&gt;Here's a simplified Python snippet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;is_market_holiday&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
 &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
 Checks if a given date is a market holiday.
 &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
 &lt;span class="c1"&gt;# Check if it's a weekend
&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;weekday&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# 5 and 6 are Saturday and Sunday
&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;

 &lt;span class="c1"&gt;# Placeholder for a more sophisticated holiday calculation.
&lt;/span&gt; &lt;span class="c1"&gt;# In a real implementation, you'd generate a list of holidays
&lt;/span&gt; &lt;span class="c1"&gt;# for the given year based on the specific market.
&lt;/span&gt; &lt;span class="c1"&gt;# This example just checks for a hardcoded Independence Day.
&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;month&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;day&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
 &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;

 &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

&lt;span class="c1"&gt;# Example usage:
&lt;/span&gt;&lt;span class="n"&gt;today&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;today&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;is_market_holiday&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;today&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
 &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;today&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; is a market holiday.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
 &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;today&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; is a trading day.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is basic. Expand it to include your actual holiday calculation logic. The key is to wrap this logic in a function that's easily called from the pipeline.&lt;/p&gt;

&lt;p&gt;Next, I dropped this holiday check into the pipeline's scheduling logic. Instead of running every day no matter what, the pipeline now checks if the target date is a trading day. If it's a holiday, the pipeline skips the data-grabbing step. It either waits until the next scheduled run or backfills the data for the previous trading day.&lt;/p&gt;

&lt;p&gt;This "backfilling" strategy is important. If the pipeline skips a holiday, you don't want to lose that day's data. Instead, you grab the data for the last &lt;em&gt;actual&lt;/em&gt; trading day.&lt;/p&gt;

&lt;p&gt;Here's how this might look in a pipeline orchestration tool:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;daily_pipeline&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="na"&gt;schedule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt; &lt;span class="c1"&gt;# Run every day at midnight&lt;/span&gt;
 &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Check if today is a market holiday&lt;/span&gt;
 &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;is_market_holiday&lt;/span&gt;
 &lt;span class="na"&gt;date&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;execution_date&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;
 &lt;span class="na"&gt;output&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;holiday_flag&lt;/span&gt;

 &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Fetch data&lt;/span&gt;
 &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;fetch_market_data&lt;/span&gt;
 &lt;span class="na"&gt;date&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;execution_date&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;1&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt; &lt;span class="c1"&gt;# Fetch data for *yesterday*&lt;/span&gt;
 &lt;span class="na"&gt;when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;holiday_flag&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;==&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;False&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt; &lt;span class="c1"&gt;# Only run if not a holiday&lt;/span&gt;

 &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Process data&lt;/span&gt;
 &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;process_data&lt;/span&gt;
 &lt;span class="na"&gt;input_data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;fetch_market_data.output_data&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;

 &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Load data&lt;/span&gt;
 &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;load_data&lt;/span&gt;
 &lt;span class="na"&gt;input_data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;process_data.output_data&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;execution_date&lt;/code&gt; is the date the pipeline is running for. The &lt;code&gt;is_market_holiday&lt;/code&gt; task decides if that date is a holiday. If it's not, the &lt;code&gt;fetch_market_data&lt;/code&gt; task grabs data for the &lt;em&gt;previous&lt;/em&gt; day (which &lt;em&gt;should&lt;/em&gt; be a trading day).&lt;/p&gt;

&lt;p&gt;This isn't perfect. It assumes that the market is always open the day &lt;em&gt;before&lt;/em&gt; a holiday. Not always true. You might need to tweak the logic to handle multiple consecutive holidays.&lt;/p&gt;

&lt;p&gt;Finally, I set up monitoring and alerting. The pipeline sends notifications if it hits an unexpected error or if the data quality checks fail. This lets me quickly spot and fix issues, including those related to holiday handling.&lt;/p&gt;

&lt;p&gt;Building a solid data pipeline? It means thinking about edge cases like market holidays. By handling these proactively, you make sure your pipeline runs reliably. And it provides good data, even when the markets are closed.&lt;/p&gt;

</description>
      <category>automation</category>
      <category>data</category>
      <category>dataengineering</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Sentiment Scoring for Finance News: A Practical Intro</title>
      <dc:creator>Stock Expert AI</dc:creator>
      <pubDate>Thu, 21 May 2026 13:00:45 +0000</pubDate>
      <link>https://dev.to/stockexpertai/sentiment-scoring-for-finance-news-a-practical-intro-1kd5</link>
      <guid>https://dev.to/stockexpertai/sentiment-scoring-for-finance-news-a-practical-intro-1kd5</guid>
      <description>&lt;p&gt;So you want to play around with sentiment analysis of finance news? Awesome. It's an interesting field, and frankly, it's not as scary as it sounds. I'll walk you through a basic but working example to get you started. This isn't an academic exercise; we're getting our hands dirty.&lt;/p&gt;

&lt;p&gt;Why bother? News articles &lt;em&gt;can&lt;/em&gt; move markets. Quantify the tone of news—is it positive, negative, or neutral about a company or asset?—and you &lt;em&gt;might&lt;/em&gt; find predictive power. Note that "might." There are zero guarantees in this game.&lt;/p&gt;

&lt;p&gt;Let's begin with the basics: text. Let's say we have this headline:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;headline = "Company X announces record profits, stock price surges"&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The simplest method is a pre-trained sentiment lexicon. Think of it as a dictionary with pre-assigned sentiment scores for words. A common one is VADER (Valence Aware Dictionary and sEntiment Reasoner). I can't tell you where to find it, but they exist.&lt;/p&gt;

&lt;p&gt;Imagine the lexicon looks like this (totally fabricated, BTW):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;lexicon&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;record&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;profits&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;surges&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;announces&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;# Could be positive or neutral
&lt;/span&gt; &lt;span class="c1"&gt;# ... lots more words ...
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Scores show how positive or negative the word is, perhaps on a scale from -1 to +1.&lt;/p&gt;

&lt;p&gt;Here's some code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;score_headline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;headline&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lexicon&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
 &lt;span class="n"&gt;words&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;headline&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;# Lowercase and split into words
&lt;/span&gt; &lt;span class="n"&gt;total_score&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
 &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;word&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;words&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
 &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;word&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;lexicon&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
 &lt;span class="n"&gt;total_score&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;lexicon&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;word&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
 &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;total_score&lt;/span&gt;

&lt;span class="n"&gt;headline&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Company X announces record profits, stock price surges&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;sentiment_score&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;score_headline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;headline&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lexicon&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Sentiment score: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;sentiment_score&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is dead simple. It sums the scores of headline words found in the lexicon. This yields a number. A positive number means positive sentiment, and the reverse is also true.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why is this too simple?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Tons of reasons. It doesn't handle negation. "Not good" should be negative, but this code treats "good" as positive and ignores the "not." It also ignores context. "Bankrupt" is bad, but "avoided bankruptcy" is different. It certainly doesn't handle sarcasm; good luck with that one. And finally, it treats all words equally, which is not ideal.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Simple improvements:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Negation Handling&lt;/strong&gt;: Look for "not," "never," or "no" before a sentiment word. If you find one, flip the sentiment score's sign.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;score_headline_with_negation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;headline&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lexicon&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
 &lt;span class="n"&gt;words&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;headline&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
 &lt;span class="n"&gt;total_score&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
 &lt;span class="n"&gt;negate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt; &lt;span class="c1"&gt;# Track negation
&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;word&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;words&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
 &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;word&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;not&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;never&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;no&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
 &lt;span class="n"&gt;negate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
 &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;word&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;lexicon&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
 &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lexicon&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;word&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
 &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;negate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
 &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="o"&gt;*=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
 &lt;span class="n"&gt;negate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt; &lt;span class="c1"&gt;# Reset negation
&lt;/span&gt; &lt;span class="n"&gt;total_score&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;score&lt;/span&gt;
 &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;total_score&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;N-grams&lt;/strong&gt;: Consider pairs or triplets of words (bigrams, trigrams). The phrase "not good" is a bigram. You'd need to grow your lexicon to include these phrases. This gets complicated fast, I promise.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Weighting&lt;/strong&gt;: Give different words different weights. Maybe "record" and "surges" matter more than "announces." Adjust the lexicon scores or use multipliers in your code to do this.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Real-World Stuff&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Lexicons are almost never perfect, and you'll probably need to customize yours. This means manually checking headlines and changing scores, or adding terms. Tedious, but needed.&lt;/p&gt;

&lt;p&gt;The subject area matters. Finance news sentiment differs from movie review sentiment. A general lexicon won't cut it.&lt;/p&gt;

&lt;p&gt;Don't just use headlines. Article bodies have more info, but processing them costs a lot more.&lt;/p&gt;

&lt;p&gt;Sentiment analysis is just one piece. Don't expect to get rich scoring headlines. It's a weak signal.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Beyond Lexicons&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Lexicon methods are simple, but limited. Advanced methods use machine learning models trained on big text datasets. These models learn more complex patterns. But they need lots of data and compute power.&lt;/p&gt;

&lt;p&gt;Sentiment scoring is fun and hard. Start simple, iterate, and don't expect miracles.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>tutorial</category>
      <category>datascience</category>
      <category>api</category>
    </item>
    <item>
      <title>Storing and Querying Time-Series Price Data Efficiently</title>
      <dc:creator>Stock Expert AI</dc:creator>
      <pubDate>Wed, 20 May 2026 18:00:59 +0000</pubDate>
      <link>https://dev.to/stockexpertai/storing-and-querying-time-series-price-data-efficiently-9ap</link>
      <guid>https://dev.to/stockexpertai/storing-and-querying-time-series-price-data-efficiently-9ap</guid>
      <description>&lt;p&gt;Okay, let's get real about time-series data, especially the kind that represents prices. I've butted heads with this problem enough times to have a few tricks up my sleeve. These can seriously save you from wanting to throw your computer out the window later. I'm talking about how to store and query data like stock prices, sensor readings, or anything else that morphs over time without wanting to pull your hair out.&lt;/p&gt;

&lt;p&gt;The first thing most people try is just dumping everything into a relational database. Sure, it &lt;em&gt;works&lt;/em&gt;. But it's like trying to run a marathon in flip-flops; you'll quickly hit a wall. Imagine logging every single price change of a stock, every second, for years. You're staring down billions of rows, and even basic queries will take an eternity.&lt;/p&gt;

&lt;p&gt;So, what's the better play? It really boils down to what you need, but here's what I've found actually works, along with some code to show you what I mean.&lt;/p&gt;

&lt;p&gt;First, get to know your data. Is it high-frequency data, like every tick of a stock? Or is it lower frequency, such as daily closing prices? This one question will shape how you store and query the data. What kind of questions will you be asking? Are you figuring out moving averages? Spotting trends? Something else?&lt;/p&gt;

&lt;p&gt;For high-frequency data, compression is your new best friend. Storing raw, uncompressed data? That's just burning money. Delta encoding is a neat trick. Instead of saving the actual price, you save the difference from the price before. If the prices are close, these deltas will be small, so you can store them using fewer bits.&lt;/p&gt;

&lt;p&gt;Here's a little Python to show you what I'm talking about:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;delta_encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prices&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
 &lt;span class="n"&gt;deltas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
 &lt;span class="n"&gt;last_price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;prices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
 &lt;span class="n"&gt;deltas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="c1"&gt;# Store the first price
&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;price&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;prices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:]:&lt;/span&gt;
 &lt;span class="n"&gt;delta&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;price&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;last_price&lt;/span&gt;
 &lt;span class="n"&gt;deltas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;delta&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="n"&gt;last_price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;price&lt;/span&gt;
 &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;deltas&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;delta_decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;deltas&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
 &lt;span class="n"&gt;prices&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
 &lt;span class="n"&gt;last_price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;deltas&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
 &lt;span class="n"&gt;prices&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;deltas&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
 &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;delta&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;deltas&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:]:&lt;/span&gt;
 &lt;span class="n"&gt;price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;last_price&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;delta&lt;/span&gt;
 &lt;span class="n"&gt;prices&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="n"&gt;last_price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;price&lt;/span&gt;
 &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;prices&lt;/span&gt;

&lt;span class="n"&gt;prices&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;10.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;10.1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;10.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;10.1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;10.3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;10.5&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;deltas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;delta_encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prices&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Original prices: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;prices&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Delta encoded: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;deltas&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Decoded prices: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;delta_decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;deltas&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's a basic example, but you get the gist. You can compress these deltas even further with variable-length encoding or fancier algorithms.&lt;/p&gt;

&lt;p&gt;Data aggregation is another big win. If you're swimming in high-frequency data, you probably don't need to hoard every single tick forever. Aggregate the data into bigger chunks of time – say, 1-minute bars, hourly bars, or daily bars. This slashes the amount of data you're storing, and it makes common queries way faster.&lt;/p&gt;

&lt;p&gt;Check out this Python snippet for a basic aggregation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pandas&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;aggregate_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;frequency&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;1H&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="c1"&gt;# Default to hourly
&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DataFrame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;timestamp&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_datetime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;timestamp&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
 &lt;span class="n"&gt;df&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;timestamp&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="n"&gt;aggregated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;price&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;resample&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;frequency&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;agg&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;first&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;last&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;min&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;max&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;mean&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
 &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;aggregated&lt;/span&gt;

&lt;span class="c1"&gt;# Example usage (assuming 'data' is a list of dictionaries with 'timestamp' and 'price')
# data = [{'timestamp': '2024-01-01 00:00:00', 'price': 10.0}, ...]
# aggregated_data = aggregate_data(data)
# print(aggregated_data)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;pandas&lt;/code&gt; makes this kind of thing a breeze. You can chop up your data into different timeframes and calculate all sorts of stats: open, close, high, low, average, and whatever else you need.&lt;/p&gt;

&lt;p&gt;And don't sleep on indexing. A standard index on the timestamp column is a start, but you might need more firepower depending on what you're asking of your data. If you're always hunting for data within a certain price range, think about a spatial index or something even more specialized.&lt;/p&gt;

&lt;p&gt;Beyond all this, your storage engine matters, a lot. Relational databases are okay for smaller datasets, but purpose-built time-series databases are often the way to go when you're dealing with serious scale. They're built for time-based queries and often have compression and aggregation baked right in.&lt;/p&gt;

&lt;p&gt;To recap: Know your data. Compress it. Aggregate it smartly. Pick the right storage engine and index it well. Do these things, and you might actually enjoy working with time-series data.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>tutorial</category>
      <category>datascience</category>
      <category>api</category>
    </item>
    <item>
      <title>MoonshotScore: Compressing Stock Analysis Into One AI Number (0–100)</title>
      <dc:creator>Stock Expert AI</dc:creator>
      <pubDate>Sun, 17 May 2026 13:24:55 +0000</pubDate>
      <link>https://dev.to/stockexpertai/moonshotscore-compressing-stock-analysis-into-one-ai-number-0-100-3fbg</link>
      <guid>https://dev.to/stockexpertai/moonshotscore-compressing-stock-analysis-into-one-ai-number-0-100-3fbg</guid>
      <description>&lt;p&gt;If you've ever researched a stock, you know the problem: you open ten tabs — financials, charts, news, analyst takes — and an hour later you're more confused than when you started.&lt;/p&gt;

&lt;p&gt;We built &lt;strong&gt;MoonshotScore&lt;/strong&gt; to fix exactly that. It's a single number from 0 to 100 that answers one question: &lt;em&gt;how much upside potential does this stock have right now?&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What goes into the score
&lt;/h2&gt;

&lt;p&gt;MoonshotScore isn't one metric dressed up — it's a blend of signals our models weigh together:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Fundamentals&lt;/strong&gt; — revenue growth, margins, debt load, free cash flow&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Technical structure&lt;/strong&gt; — trend, momentum, support and resistance&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sentiment&lt;/strong&gt; — news flow and how the market is positioned&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Valuation&lt;/strong&gt; — is the price ahead of the story, or behind it?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each stock is re-scored as new data arrives, so the number reflects &lt;em&gt;now&lt;/em&gt; — not last quarter.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Legends Council
&lt;/h2&gt;

&lt;p&gt;Numbers alone miss nuance, so we layered on perspective. The &lt;strong&gt;Legends Council&lt;/strong&gt; runs each stock through the lens of investing legends — Buffett's quality focus, Dalio's macro caution, Lynch's growth-at-a-reasonable-price, Simons' quant rigor. You see where they'd agree, and where they'd argue.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why a single number?
&lt;/h2&gt;

&lt;p&gt;Because decisions need an anchor. MoonshotScore doesn't tell you to buy — it tells you where to &lt;em&gt;look first&lt;/em&gt;. A 78 means "dig in." A 31 means "probably skip it." It turns a two-hour research session into a two-minute filter.&lt;/p&gt;

&lt;p&gt;We cover 35,000+ stocks, and it's free to use.&lt;/p&gt;

&lt;p&gt;👉 Try it: &lt;a href="https://stockexpertai.com" rel="noopener noreferrer"&gt;stockexpertai.com&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;If you were designing a score like this, what would you want it to factor in? Curious to hear takes in the comments.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>finance</category>
      <category>machinelearning</category>
      <category>data</category>
    </item>
  </channel>
</rss>
