← Back to list

Don’t Run Today’s Trades Without These 7 Pandas Moves — Part 1

This is part one of my three part series on using Python + Pandas for real trading and investing workflows, and there is a bonus content…

Zaid Alissa Almaliki · 2025-06-08 12:15 · 1 claps · 4.9 min read paywalled
#trading-system #pandas #wrangling #investing #sentiment-analysis
Open on Medium ↗
Wiki topics: INV · Investing & Markets

Don’t Run Today’s Trades Without These 7 Pandas Moves — Part 1

This is part one of my three part series on using Python + Pandas for real trading and investing workflows, and there is a bonus content at the end to solve one of the big issues that we all have with Yahoo Finance since the start of 2025.

Source of image

Source of image

Table of Contents:

  1. **Why I Wrote This.**
  2. **Step 1: Load Some Real Market Data.**
  3. **Step 2: Calculate Daily Returns.**
  4. **Step 3: Deal with Missing Data.**
  5. **Step 4: Compare Two Stocks Side by Side.**
  6. **Step 5: Spot the High-Volatility Days.**
  7. **Step 6: Create a Simple Trend Indicator.**
  8. **Step 7: Label Bull, Neutral, and Bear Regimes.**
  9. **ELI5: How the 20-Day Cumulative Return Bucket Works.**
  10. **What You’ve Learned So Far.**
  11. **One Practical Use Case: Filter Trades on Volatile Days.**
  12. **Bonus Content: There is a big issue now with Yahoo Finance.**
  13. **What’s Next in Part 2: Strategy and Portfolio Logic**
  14. **Conclusion.**

Why I Wrote This

A few years ago, I built my first trading strategy in Excel. It worked, sort of — until it didn’t. Formulas would break. Data would go missing. The whole thing felt fragile. So I switched to Python. Pandas was the tool everyone talked about. But when I tried to use it for actual trading logic — moving averages, backtests, volatility filters — I hit a wall. The syntax was weird. Most tutorials used fake data. And no one explained how real traders actually think. This series is my attempt to fix that. You’ll be working with real stock data, building logic to detect trends, label market regimes, and build reusable strategy tools that feel closer to how actual quants and algo traders operate. Let’s get into it.

Step 1: Load Some Real Market Data

We’ll use yfinance to pull Apple (AAPL) stock data — it’s free, reliable enough, and perfect for this kind of work.

!pip install curl_cffi yfinance pandas
import yfinance as yf
import pandas as pd
import time

aapl = yf.download("AAPL", session=session,start="2020-01-01", end="2024-01-01")
print(aapl.head)

This gives you a tidy time-indexed DataFrame: open, high, low, close, volume. Close which is what we care about most. That column adjusts for dividends and stock splits, making it a better input for return-based analysis.

Step 2: Calculate Daily Returns

In finance, price is what you pay. But returns are what really matter.

aapl['Daily Return'] = aapl['Close'].pct_change()
aapl['Daily Return'].plot(title="AAPL Daily Returns")

This gives us the percentage change in price from one day to the next — the foundation of all performance, volatility, Sharpe ratios, and drawdown calculations. It’s also the raw material for every strategy you’ll ever build.

Step 3: Deal with Missing Data

Financial data has holes — holidays, outages, weird gaps from the data provider. Don’t let it break your backtest.

aapl['Close'].isna().sum()
aapl.iloc[5:10, aapl.columns.get_loc('Close')] = None
aapl['Close'].isna().sum()
aapl.iloc[4:11, aapl.columns.get_loc('Close')]
aapl['Close'] = aapl['Close'].fillna(method='ffill')
aapl.iloc[4:11, aapl.columns.get_loc('Close')]

This line keeps your strategy running even when there’s no new data. It’s not fancy, but in the real world, it’s necessary.

Step 4: Compare Two Stocks Side by Side

Want to see how Apple did vs Microsoft? Normalize both to $1 on day one:

msft = yf.download("MSFT", start="2020-01-01", end="2024-01-01")
combined = pd.DataFrame({
    'AAPL': aapl['Close']['AAPL'],
    'MSFT': msft['Close']['MSFT'],
})

normalized = combined / combined.iloc[0]
normalized.plot(title="AAPL vs MSFT (Normalized to $1)")

This shows how $1 invested in each company grew over time — a clean, intuitive way to compare performance.

Step 5: Spot the High-Volatility Days

Let’s say you’re building a risk model. You might want to skip trades on days when volatility is too high.

high_vol = aapl[aapl['Daily Return'].abs() > 0.021]
print(high_vol[['Close', 'Daily Return']].head())

Here, we’re filtering for days when Apple moved more than ±2%. You’d be surprised how often those days cluster around earnings reports or macro news. You can also use this to build “volatility filters” that pause your strategy when the market gets too jumpy.

Step 6: Create a Simple Trend Indicator

Let’s introduce one of the most classic technical indicators: the moving average.

close_series = aapl['Close']['AAPL']
aapl['20D MA'] = close_series.rolling(window=20).mean()
aapl['Trend Signal'] = (close_series > aapl['20D MA']).astype(int)

This Trend Signal column will be 1 when the price is above the 20-day moving average (bullish), and 0 when it’s below (bearish). It’s the backbone of hundreds of trend-following systems — from simple bots to hedge fund models.

Step 7: Label Bull, Neutral, and Bear Regimes

Let’s go a step further: use rolling returns to define whether the market is currently in a bull, neutral, or bear regime.

aapl['20D Cum Return'] = aapl['Daily Return'].rolling(window=20).sum()
aapl['Market Regime'] = pd.cut(
    aapl['20D Cum Return'],
    bins=[-1, -0.05, 0.05, 1],
    labels=['Bear', 'Neutral', 'Bull']
)
aapl[['Daily Return','20D Cum Return','Market Regime']].tail(11)

ELI5: How the 20-Day Cumulative Return Bucket Works

Now every day has a label. You can use this to change risk levels, switch strategies, or even just better visualize your backtests. For a more ELI5 explanation of the code read this please:

If over the last 20 days you had returns of +0.5%, +0.7%, –0.2%, … up to day 20, summing them gives you something like +8.3% total.

For dates before you have 20 days of history, you’ll see NaN because there isn’t a full window yet.

Anything ≤ −5% (down 5% or more in 20 days) falls into the first bucket. If your 20-day cumlative return is −8%, it becomes bear.

Between −5% and +5% is considered neutral. If it’s +2%, it’s neutral.

Anything ≥ +5% is the bull bucket. If it’s +12%, that’s definitely bull territory.

What You’ve Learned So Far

What You Built Why It Matters Daily Returns Basis for any kind of trading strategy Fill Missing Data Avoid silent errors or broken pipelines Stock Comparisons Track relative performance over time Volatility Filter Avoid high-risk trades or events Moving Average Signal Momentum/trend entry-exit logic Regime Detection Dynamic strategy switching / allocation.

One Practical Use Case: Filter Trades on Volatile Days

Imagine you have a signal to buy AAPL. But you only want to enter when the market is “calm.”

Just use this:

signal = (aapl['Trend Signal'] == 1)
not_too_volatile = (aapl['Daily Return'].abs() < 0.021)
filtered_signal = signal & not_too_volatile

You’ve just created a strategy filter that only buys when the trend is up and volatility is manageable.

Bonus Content: There is a big issue now with Yahoo Finance.

import yfinance as yf
import pandas as pd
import time
from curl_cffi import requests

session = requests.Session(impersonate="chrome")
aapl = yf.download("AAPL", session=session,start="2020-01-01", end="2024-01-01")
msft = yf.download("MSFT", session=session,start="2020-01-01", end="2024-01-01")
print(aapl.head)

If you do it the old way, like you did in the first step you will have this error

YFRateLimitError('Too Many Requests')

so in order to avoid the error you need to use curl_cffi package and use a session.

In Part 2: Strategy and Portfolio Logic

In Part 2, we’ll start putting these tools into motion:

  • Resample daily data into monthly
  • Build a simple moving average crossover strategy
  • Simulate a 60/40 portfolio with SPY and AGG
  • Measure Sharpe ratio and max drawdown
  • Rank ETFs by momentum

Conclusion

If this article saved you an hour or two of Googling — or got you excited to build your own trading notebook — send it to a friend or give me a like. If you’d like me to turn all 3 parts into a downloadable notebook or GitHub repo, let me know in the comments below.


메타데이터
post_id
490ea94ffaee
slug
dont-run-today-s-trades-without-these-7-pandas-moves-part-1-490ea94ffaee
url
https://medium.com/@dataakkadian/dont-run-today-s-trades-without-these-7-pandas-moves-part-1-490ea94ffaee
canonical_url
https://medium.com/@dataakkadian/dont-run-today-s-trades-without-these-7-pandas-moves-part-1-490ea94ffaee
author_url
https://medium.com/@dataakkadian
status
ok
fetched_at
2026-07-30 18:47:05