How to Find the Worst-Performing Stocks in Your Portfolio Using Python

Day 72 of 100 Days Coding Challenge: Python

Yesterday, I was busy shining the spotlight on my star performers—the stocks that strutted across the stage as Broadway leads. Today, it was time to peek behind the curtain and see who was tripping over their own shoelaces. Enter: the “Worst-Performing Stock Tracker” function.

The logic is the same as yesterday’s “Best Performer” feature, but instead of crowning heroes, this one identifies the stragglers. Why bother? Because good portfolio management isn’t just about celebrating your winners—it’s also about recognizing when something is quietly dragging you down. I use it as a reminder to rebalance, pairing losses with gains. Thanks to yesterday’s groundwork, adding this feature felt like running downhill instead of uphill.

Today’s Motivation / Challenge

This project matters because no portfolio is a utopia of green arrows. Every investor has that one stock sitting in the corner sulking, ruining the vibe. By building a tool that identifies these underperformers, you can make better decisions: cut your losses, reallocate funds, or at least brace yourself with an extra cup of coffee before checking your account.

Purpose of the Code (Object)

The code checks your portfolio over the past X days (7, 14, or 30) and identifies the worst performer. It then neatly lists the bottom 10, so you can see at a glance which ones are dragging your imaginary—or real—portfolio down. Think of it as a “naughty list” for your investments.

AI Prompt

Add a function to show Worst Performer (last X days). Identify the stock dragging your (imaginary) portfolio down and display the bottom 10 over 7, 14, or 30 days.

Functions & Features

  • Add, remove, and view tracked stocks.
  • Fetch real-time prices.
  • Check best and worst performers over selectable periods.
  • Simulate portfolio performance and rebalance strategies.

Requirements / Setup

  • Python 3.9+

Install dependencies:

pip install yfinance pandas matplotlib

Minimal Code Sample

def worst_performer_last_x_days(symbols, days=7):

    results = []

    for sym in symbols:

        closes = _get_closes_1d(sym, period_days=days+5)

        if closes is None or len(closes) < days + 1:

            continue

        start, end = float(closes.iloc[-(days+1)]), float(closes.iloc[-1])

        pct = (end – start) / start * 100

        results.append({“symbol”: sym, “pct”: pct})

    return sorted(results, key=lambda r: r[“pct”])[:10]  # bottom 10

This function sorts your portfolio by performance and hands you the 10 worst offenders.

Stock Tracker

Notes / Lessons Learned

I made sure the function pulls from the same stocks.json file used by other features, keeping everything consistent. That’s like making sure all your socks match before heading out—details matter.

What surprised me? Debugging an error in my “simulate portfolio value” function. I suspect it’s tied to the line grabbing the first close price, but that’s a mystery for another day. The fun (and slightly maddening) part of coding is how today’s victory sometimes reveals tomorrow’s bug. Keeps life interesting, doesn’t it?

Optional Ideas for Expansion

  • Add a “Worst Sector” view to see which industry is letting you down the most.
  • Build a feature that pairs losers with winners for auto-rebalancing.
  • Compare your bottom 10 to the S&P 500 and see if misery loves company.

Build a Portfolio Performance Checker in Python

Day 71 of 100 Days Coding Challenge: Python

Today, I added a feature to crown the “best performer” from my portfolio. Think of it as a mini award ceremony where only stocks are invited and there’s no acceptance speech—just numbers. The function itself is simple: it checks which stocks in my holdings have gained the most over the last 7, 14, or 30 days. I don’t need this every day; daily stock swings are more like background noise than useful insight. In fact, when I first started, I used to check every single day—bad idea. The constant up-and-down did nothing but feed my anxiety. Now, I prefer to take a step back and do a weekly review, usually on weekends. That’s when I reflect, think strategically, and make any adjustments.

I’m more of a mid-term investor, not a hyperactive day trader, so this tool fits right into my rhythm. It’s like glancing at the scoreboard after a few innings rather than obsessing over every pitch.

Today’s Motivation / Challenge


The challenge was to build a function that helps me zoom out. Beginners (my past self included) often get caught up in every twitch of the market. But sometimes, what you need is a bird’s-eye view: Which of my stocks has been pulling its weight lately? This function answers that without the clutter of daily drama.

Purpose of the Code (Object)


This code identifies which stock in your portfolio had the biggest gain over a chosen period—7, 14, or 30 days. It’s essentially a quick performance check-up for your holdings, designed to keep you focused on trends rather than noise.

AI Prompt


Use the file uploaded, and add the function to see Best Performer (last X days): Identify the top gainer over the last 7, 14, or 30 days.

Functions & Features

  • Add and remove stock symbols from your portfolio
  • Track daily changes and simulate allocations
  • Plot historical charts and moving averages
  • Check diversification and sector exposure
  • New: Spot the best performer over 7, 14, or 30 days

 You’ll need Python 3 and a few common libraries:

pip install yfinance pandas matplotlib

Minimal Code Sample

winner, results = best_performer_last_x_days(symbols, days=7)

print(f”Best performer (7 days): {winner[‘symbol’]} {winner[‘pct’]:.2f}%”)

This snippet finds the top gainer in your current portfolio over the past 7 days.

Stock Tracker

Notes / Lessons Learned


Today, I learned how a tiny inconsistency can wreak havoc. My script is now over 1,300 lines, and I initially got nothing but “no results” because the function was pulling symbols from the wrong place. I mistakenly used get_symbols() from portfolio.json, while the rest of the app stores tickers in stocks.json through load_stocks(). Naturally, the poor function came up empty. The quick fix was to swap in load_stocks(). It reminded me of those group projects where one person keeps using a different spreadsheet version—chaos ensues. Moral of the story: keep your files consistent, keep your sanity intact.

Optional Ideas for Expansion

  • Add a “Worst Performer” twin function, so you know which stock deserves detention.
  • Compare your portfolio’s best performer against the S&P 500 for context.
  • Create a simple chart that ranks the top 5 movers for a more visual snapshot.

The Snack Experiment: Kidney Friendly Snacks

Brian’s fitness journal after a brain stroke

Lately, I’ve been rotating my snacks like a cautious scientist running a very personal experiment. The goal is simple: keep my weight steady. The execution, unfortunately, is not.

Because I run regularly, exercise, and even mow the lawn during warmer months, my activity level is fairly high. That sounds healthy in theory. In practice, it makes maintaining weight surprisingly difficult. My body burns energy enthusiastically, while my dietary options remain… diplomatically restricted.

Kidney conditions come with a long list of nutritional negotiations. I cannot rely on protein shakes like a typical active adult, since compromised kidneys struggle to filter metabolic waste such as urea. Potassium, phosphorus, and excess sodium also require careful monitoring. Suddenly, many “healthy snacks” become suspicious characters.

Bananas? Too much potassium.
Melons? Also potassium.
Convenient snacks? Usually salty.

At this point, even the snack aisle feels like a minefield disguised as a grocery store.

Naturally, I tried switching to melons as a safer alternative—only to discover they also contain a fair amount of potassium. That plan was quietly retired. I then pivoted to berries, which are much more kidney-friendly. The only problem? They are good… and aggressively sour.

So, I introduced a diplomatic solution: homemade yogurt.

My wife makes yogurt at home, which is both versatile and practical. It works in smoothies, cooking, and even as a substitute for sour cream. Recently, I suspect she has been making more of it simply because I keep eating it. I am now seriously considering taking over yogurt production myself. Not because it is difficult, but because it requires careful temperature control when adding the culture—something my wife has been handling with quiet precision.

Today brought an encouraging result. I finally regained some of the weight I had been missing: 1.2 pounds, with 0.8 pounds recorded as muscle mass. I am still slightly under my target range, but less so than yesterday, which counts as meaningful progress.

Yesterday’s snack experiment consisted of a small bowl of yogurt paired with blackberries. It is entirely possible that this combination helped reverse the downward trend. Of course, one data point does not make a scientific conclusion—but it does make a promising hypothesis.

Therefore, in the spirit of disciplined experimentation (and cautious optimism), I will repeat the yogurt-and-berries protocol again this evening.

I hope this will solve my problem.

Build a Portfolio Sector Weight Analyzer in Python

Day 70 of 100 Days Coding Challenge: Python

Yesterday’s mission was neat labels; today’s mission is guardrails. After building a sector classifier, I wired up a real diversification warning that uses my actual holdings. Diversification isn’t a hedge against everything, but it’s a reliable seatbelt against unsystematic risk—the “one company or one industry sneezes, and my portfolio catches a cold” problem. During COVID, anyone parked entirely in hospitality learned this the hard way.

This little alarm is more than a nag; it’s a planning tool. You can use it for sector rotation, thematic tilts, or just sanity checks alongside momentum and RSI. I also like it for quick overlap checks: if a few ETFs secretly pile into the same sector, this makes the crowding visible. Honestly, the feature pays off all the tiny utilities I’ve been adding—now they sing together instead of humming alone.

Today’s Motivation / Challenge

I wanted a single, honest number that says, “Are you concentrated or not?” The challenge: turn tickers into sectors, sectors into dollars, and dollars into weights—without burying the user in math or menus.

Purpose of the Code (Object)

The program reads your tracked tickers and your share counts, fetches current prices, and calculates market value per holding. It then groups by sector (treating multi-sector and bond ETFs as their own diversified buckets) and shows each sector’s weight. If any one slice is larger than your chosen threshold, you get a clear warning.

AI Prompt

“Refactor the diversification function to be small, readable, and robust. Keep inputs flexible, handle ETFs cleanly, and print a concise sector weight table followed by any threshold warnings.”

Functions & Features

  • Record or update shares for each tracked symbol.
  • Classify holdings by sector, with special handling for multi-sector and bond ETFs.
  • Compute sector weights using Market Value = Shares × Price.
  • Trigger a diversification warning if any sector exceeds a threshold (e.g., 35%).

Requirements / Setup

  • Python 3.10+

Install:

pip install yfinance pandas matplotlib

Minimal Code Sample

def sector_weights(rows, threshold=0.35):

    # rows: list of {symbol, sector, shares, price}

    df = pd.DataFrame(rows)

    df[“market_value”] = df[“shares”] * df[“price”]

    total = df[“market_value”].sum()

    if total <= 0:

        return {}, []

    weights = (df.groupby(“sector”)[“market_value”].sum() / total).sort_values(ascending=False)

    offenders = [(s, w) for s, w in weights.items() if w >= threshold]

    return dict(weights), offenders

Compute sector weights from actual dollars; return all weights plus any over the threshold.

Stock Tracker

Notes / Lessons Learned

I initially forgot to store share counts. Which meant every stock was treated like I owned exactly one share—cute for demos, terrible for truth. I was sure I’d written a “set shares” function before; apparently Past Me left Future Me a polite illusion. Once I added a quick way to save shares in stocks.json, the numbers snapped into place.

The joy here is leverage: Python fetches prices, lines up sectors, and crunches totals in seconds. What used to be a spreadsheet slog is now a button press. Also, beware ETF overlap—their tickers look diverse, but their guts sometimes aren’t.

Optional Ideas for Expansion

  • Add “max sector cap” rules per account and print suggested trades to rebalance.
  • Show a tiny trendline of each sector’s weight over time (store daily snapshots).
  • Include an “overlap matrix” for ETFs using their published holdings, if available.

Know Thy Sector Before Thy Portfolio Falls Apart

Day 69 of 100 Days Coding Challenge: Python

Today’s stop on the Stock Tracker Express was “Sector Classification,” and I decided to pull into that station before the Diversification Warning stop. Why? Because you can’t warn about lopsided allocations until you know where your money is hiding. Sector classification is like labeling your pantry—if you find 14 jars of peanut butter and no pasta, you might reconsider your meal plan.

In investing, this helps spot “unsystematic risk,” which is just the fancy way of saying, “If one company or industry tanks, you don’t want your whole portfolio going down with it.” Sometimes, yes, you might choose to overload in one sector—maybe tech is hot or utilities are shining—but the point is to know when you’re doing it. With the sector view in place, you can pair it with performance metrics, macroeconomic signals, or just your gut to make better decisions. My roadmap had diversification before classification, but order matters—this way, we start with a map before we set up roadblocks.

Today’s Motivation / Challenge

If you’ve ever played a board game without reading the rules first, you’ll understand why knowing your sector exposure before diversifying is important. Classification turns a pile of tickers into an organized story, letting you see not just what you own, but where it lives.

Purpose of the Code (Object)


This function takes your tracked tickers, peeks under the hood, and tells you what sector and industry they belong to. For ETFs and funds, it makes an educated guess—flagging them as multi-sector or fixed income when appropriate. The idea is to give you a quick visual of portfolio balance before you go hunting for weak spots.

AI Prompt

Creates the following functions: Fetch sector and industry, identify ETFs and label them as multi-sector or fixed income, and finally print a tidy classification table and sector summary.

Functions & Features

  • Fetch sector and industry data for each tracked stock.
  • Identify ETFs and label them as multi-sector or fixed income.
  • Print a tidy classification table and sector summary.
  • Optionally export results to CSV.

Requirements / Setup

  • Python 3.10+

Install dependencies:

pip install yfinance pandas matplotlib

Minimal Code Sample

import yfinance as yf

def get_sector(symbol):

    info = yf.Ticker(symbol).info

    return info.get(“sector”), info.get(“industry”)

print(get_sector(“MSFT”))  # (‘Technology’, ‘Software—Infrastructure’)

Pulls sector and industry info for a ticker.

Stock Tracker

Notes / Lessons Learned

ETFs can be divas—some announce their sector proudly, others just say “multi-sector” or “bond fund” and walk away. Fixed income ETFs (bond funds) make perfect hedges for my tech-heavy holdings, so I labeled those separately. This classification step also reminded me how ambiguous data can be; without it, I might’ve assumed my ETFs were more focused—or more diversified—than they really are.

Optional Ideas for Expansion

  • Show top three sector weights for ETFs when available.
  • Include historical sector rotation charts.
  • Add filters to display only certain sectors.

Running In Cold Weather Because Goals Don’t Care About Temperature)

Brian’s fitness journal after a brain stroke

The chilly morning didn’t deter my wife from her early exercise routine. It also didn’t deter her from running errands. She planned a trip to the UPS Store to return an Amazon package and invited me along. I happily agreed. Marriage sometimes means love; sometimes it means carrying the return receipt.

Because the morning air was brutally cold, I decided to delay my run until later in the day. Ever since my brain stroke, temperature regulation hasn’t exactly been my body’s strong suit. My neurologist explained that my autonomic nervous system took a hit. In practical terms, that means my body takes longer to warm up—and running in freezing air feels like negotiating with winter while already tired.

When it’s cold, my body spends energy heating itself before it even starts running. It’s like paying an entrance fee before the workout even begins.

Still, cold weather does not cancel Saturday’s 10K.

Goals don’t reschedule themselves.

Starting the run was the hardest part. My muscles felt stiff, and the air felt unfriendly. But once I got moving, rhythm returned. The first half of the run went surprisingly well—I actually hit my target pace. I briefly entertained the idea of conquering the entire distance at that speed.

The second half had other ideas.

I couldn’t quite maintain the pace, but the overall result was still strong enough to earn my third-fastest 10K ever. That’s not perfection, but it’s progress—and progress is what counts.

What encourages me most is the trajectory. I’m slowly getting faster. Not dramatically. Not magically. But steadily.

There’s still plenty of work ahead if I want to hit this year’s goal. But it’s early in the year. Improvement doesn’t require heroics; it requires repetition. As long as I keep showing up, struggling a little, and pushing just past comfort, I’ll keep improving.

Winter can complain all it wants.

I’ll keep running.

Stock Momentum Indicator Made Simple: Compute Trend Direction with Python

Day 68 of 100 Days Coding Challenge: Python

Yesterday’s three-hour duel with RSI left me a little cross-eyed, so I returned today with a reset brain and a mission: add a Stock Momentum Indicator. I’m not a chart whisperer, but this little gauge helps me decide which stocks deserve a spot on the keep list and which ones can politely see themselves out. Of course, no single indicator is a magic “buy/sell” button—RSI and moving averages still earn their keep, and a quick skim of headlines never hurts. If a name like TSLA suddenly lurches up or down, momentum usually lights up first, and that’s my cue to check the news and sanity-check my long-term plan. I’m investing for the marathon, not the sprint; momentum just helps me keep my shoelaces tied.

Today’s Motivation / Challenge

Prices wiggle. Trends matter. The challenge is turning those squiggles into a simple “up, down, or meh” signal you can read in one glance—something practical enough to use with your existing RSI/MA checks without turning your brain into soup.

Purpose of the Code (Object)

The Momentum Score looks at recent closing prices, fits a straight line through them, and tells you if the general direction is up, down, or flat. It also weighs how “clean” the trend is so wobbly lines don’t shout as loudly as steady climbs. You get a single number plus a label that’s easy to act on.

AI Prompt

“Make this function cleaner. Keep inputs/outputs simple, follow PEP 8, handle edge cases (short/NaN data), add concise docstrings, and avoid side effects. Return a small dict with last_close, ann_pct, r2, score, and direction. Prefer readable names over cleverness.”

Functions & Features

  • Momentum Score: Up/Down/Flat with a strength-weighted score.
  • RSI status: Quick read on overbought/oversold.
  • Moving Averages: Short vs. long for context.
  • Fetch recent closes: Pulls the last N days for each ticker.

Requirements / Setup

  • Python 3.10+

Install:

pip install yfinance pandas numpy matplotlib

Minimal Code Sample

def momentum_score(closes, lookback=60):

    s = pd.Series(closes).dropna().astype(float).tail(lookback)

    if len(s) < 20:

        return {“direction”: “flat”, “score”: 0.0, “r2”: 0.0, “ann_pct”: 0.0, “last_close”: float(‘nan’)}

    y = s.values

    x = np.arange(len(y), dtype=float)

    slope, intercept = np.polyfit(x, y, 1)

    y_hat = intercept + slope * x

    ss_res = np.sum((y – y_hat) ** 2)

    ss_tot = np.sum((y – y.mean()) ** 2)

    r2 = 0.0 if ss_tot == 0 else max(0.0, 1.0 – ss_res / ss_tot)

    ann_pct = (slope / np.mean(y)) * 252.0 * 100.0

    score = ann_pct * r2

    direction = “up” if score > 1 else “down” if score < -1 else “flat”

    return {“direction”: direction, “score”: score, “r2”: r2, “ann_pct”: ann_pct, “last_close”: float(s.iloc[-1])}

Fits a straight line through recent prices, scales the slope to annualized %, weights by trend quality (R²), and labels the direction.

Stock Tracker

Notes / Lessons Learned

Yesterday taught me a simple truth: sometimes the best fix is a fresh chat and a tidier workspace. I kept stuffing more context into the same thread and the AI started juggling chainsaws. Uploading the project folder and the roadmap calmed everything down—clean inputs, clean outputs, faster help. People get overwhelmed by messy instructions; AI does too (just less visibly).

Under the hood, momentum is pleasantly un-mystical. Grab the last N closes (I like 60), draw a line, scale the slope to an annualized percentage, weight it by how straight that line is, and call it: up, down, or flat. It runs in seconds, which is delightful—just remember fast ≠ infallible. Spiky data, low volume, or surprise news can throw elbows, so pair this with RSI, moving averages, and a quick look at headlines before you make grown-up decisions.

Optional Ideas for Expansion

  • Add a tiny sparkline plot with the regression line for each ticker.
  • Auto-flag “momentum flips” (e.g., score crosses ±1) and show the last few related headlines.
  • Let each symbol have its own lookback window so slow movers and high fliers get fair treatment.

Stock RSI Made Simple: Calculate Overbought & Oversold Conditions in Python

Day 67 of 100 Days Coding Challenge: Python

Today’s experiment was all about giving my stock tracker a sixth sense—adding the Relative Strength Index (RSI), RSI Stock Indicator . Think of RSI as the mood ring of the trading world: if it reads over 70, your stock might be partying too hard and due for a hangover (price pullback). Under 30? That’s the sulking, underappreciated stock that might be ready to rally.

Now, RSI isn’t the crystal ball some traders wish it was, but it’s a handy companion—especially when paired with the moving average I added yesterday. It’s popular for a reason: it’s simple, visual, and just a little bit addictive. The fun part is seeing it tell a different story than the price chart itself, which feels a bit like watching a behind-the-scenes documentary instead of just the movie.

Today’s Motivation / Challenge

I wanted to give my tracker more “personality” by adding an indicator that can hint when prices might reverse. Also, part of me just wanted to prove to myself that I could wrestle with the math, the formatting, and Yahoo Finance’s occasional mood swings—and win.

Purpose of the Code (Object)

This code calculates the RSI for each stock I’m tracking, then tells me whether each one might be overbought, oversold, or just sitting in the middle lane. It takes the raw price data, does a little statistical gymnastics, and spits out a number that’s easy to read, even if you’ve never taken a finance class.

AI Prompt

Add an RSI tracker to my existing Code

Functions & Features

  • Calculate the 14-day RSI for each tracked stock.
  • Flag stocks as overbought (≥70), oversold (≤30), or neutral.
  • Handle messy or missing data without breaking the whole program.

Requirements / Setup

  • Python 3.x
  • pip install yfinance pandas numpy matplotlib

Minimal Code Sample

def _compute_rsi(series, period=14):

    delta = series.diff()

    gain = delta.clip(lower=0)

    loss = -delta.clip(upper=0)

    avg_gain = gain.ewm(alpha=1/period, adjust=False).mean()

    avg_loss = loss.ewm(alpha=1/period, adjust=False).mean()

    rs = avg_gain / avg_loss

    return 100 – (100 / (1 + rs))  # RSI formula

Calculates the RSI from closing prices using Wilder’s smoothing.

Stock Tracker

Notes / Lessons Learned


If there’s one thing RSI taught me, it’s that the market isn’t the only thing that can get moody—code can too. I ran into a storm of “err arg must be…” errors when pandas didn’t like the format of the data coming from Yahoo Finance. It wasn’t just the low-volume ETFs either; even TSLA decided to throw a tantrum. I tried to fix it, and in the process, managed to break other parts of my program.

After a frustrating 150 minutes of debugging, I threw in the towel and started fresh. One hour later—miracle!—it worked. The fixes? Making value conversions safer, checking Series length before indexing, and printing clear error messages. Then came the “not 1-D” ambush—some tickers return MultiIndex columns, which threw my code into existential crisis. The solution was to always extract a clean 1-D float series before running calculations. Now it runs without cryptic complaints, and I finally feel like I’ve tamed it… for now.

Optional Ideas for Expansion

  • Plot RSI alongside the price chart for a quick visual check.
  • Let the user choose the RSI period length (not just 14 days).
  • Add alerts for when a stock crosses the overbought/oversold thresholds.

Cold Weather Survival: Hoodies, Habits, and a Mischievous Kitten

Brian’s fitness journal after a brain stroke

Temperatures continue their dramatic plunge, but at least today I had the privilege of staying indoors. Unfortunately, it was laundry day—which means for several tragic hours, I was deprived of my robe and my properly functioning hoodie.

Yes, I do have a backup hoodie.
No, its broken zipper does not inspire confidence.
Wearing it feels like wearing a coat that refuses to commit.

So, for a few chilly hours each week, I endure mild suffering while the dryer does its heroic work. It’s temporary discomfort. I’ve decided not to engineer a complex solution. I can survive three hours of inconvenience without launching a research project.

We were spoiled by an unusually warm Christmas, so these low-20°F days feel especially rude. Meanwhile, my wife still goes outside for her morning exercise as if she personally signed a treaty with winter. She has Canadian credentials and a winter jacket that appears to be indestructible. I suspect it could survive the next ice age.

I now own warm running pants, which has significantly reduced my outdoor complaints. Oddly enough, I feel colder inside the house. My wife keeps it at 65°F. It’s not unbearable—just motivational. Since last year, I’ve adopted a simple solution: if I feel cold, I plank.

It’s efficient.

  • I get stronger.
  • I get warmer.
  • I stop whining.

Exercise as central heating. Highly recommend.

Our cat, meanwhile, has discovered that I radiate heat. According to my wife, I am apparently a “portable furnace.” The kitten agrees. She camps on my lap while I work, converting me into a heated workstation.

However, this same angel becomes chaos incarnate at night. She developed the charming habit of attacking her toy mouse at 2:00 AM directly on our bed. Nothing says deep sleep like sudden feline warfare.

My solution: confiscate the mouse before bedtime.

Her solution: hide the mouse somewhere I can’t find it.

She’s entering what my wife calls “cat adolescence”—a stage characterized by selective hearing and bold experimentation. Recently, she’s decided that kitchen counters are now part of her sovereign territory. She’s stronger and more muscular than our older cat and enjoys launching herself onto elevated surfaces like a tiny Olympic gymnast.

The problem arises when I’m cooking.

There is something mildly alarming about a cat leaping toward the counter while I’m holding a knife. I gently relocate her to the floor. She complains loudly, as if I’ve unjustly exiled her from culinary greatness.

Between the cold house, strategic planking, and a counter-climbing kitten, winter remains lively.

At least I’m never bored.

The Long and Short of It: Moving Averages for Lazy Traders

Day 66 of 100 Days Coding Challenge: Python

I’ve added a new trick to my stock tracker: the moving average. Think of it as the “Zen master” of stock analysis—calm, collected, and uninterested in daily drama. I set it up so I can see both the short-term (7-day) moving average, which catches the mood swings, and the long-term (30-day) moving average, which reveals the bigger picture. Short-term trends tell you if a stock is suddenly sprinting, while long-term averages show if it’s been strolling uphill—or slowly rolling downhill—over time.

In finance, we do this on all sorts of timelines: monthly, quarterly, yearly. I’m not a day trader, so this isn’t about chasing every market twitch. Instead, this helps me filter out noise and focus on the broader trend—much like ignoring the gossip at the office and paying attention to the quarterly earnings report. In the future, I’d like to use this to spot “support” and “resistance” levels—that is, the invisible floor and ceiling where prices tend to bounce.

Today’s Motivation / Challenge

Daily stock prices are a roller coaster. Fun if you like screaming every 3 seconds, exhausting if you actually want to get somewhere. Moving averages smooth out the ride, letting you see if the track is going up, down, or looping sideways.

Purpose of the Code (Object)

This feature takes the recent stock prices for each symbol, calculates the 7-day and 30-day averages, and compares them to the most recent closing price. The result: a quick glance at short-term momentum versus long-term direction, without getting blinded by daily price noise.

AI Prompt

“Add a function to track the 7-day and 30-day moving averages of listed stocks, comparing each to the last closing price, and display the results clearly.”

Functions & Features

  • Calculates 7-day and 30-day simple moving averages (SMA).
  • Compares latest price to SMA values.
  • Displays trends for quick decision-making.

Requirements / Setup

pip install yfinance pandas

Minimal Code Sample

closes = hist[‘Close’]

last = float(closes.iloc[-1])  # Get most recent closing price

sma7 = closes.rolling(window=7).mean().iloc[-1]

sma30 = closes.rolling(window=30).mean().iloc[-1]

Calculates the last closing price and both moving averages.

Stock Tracker

Notes / Lessons Learned

The first time I ran this, Pandas wagged its finger at me with a “FutureWarning” about float(series). Apparently, in Pandas 2.2+, turning a whole Series into a single float is too vague. Imagine handing a librarian a 300-page book and saying, “Turn this into a number.” Which page, line, or word? Pandas now demands you be explicit:

  • .iloc[0] → picks the first element.
  • .item() → converts it directly to a Python number.

Once I cleaned up the code and restarted, it ran like a charm. And honestly, seeing my own program spit out these averages feels much better than refreshing some finance site.

Optional Ideas for Expansion

  • Add a chart to visualize SMA crossovers.
  • Let the user set custom time windows for moving averages.
  • Include alerts when the short-term average crosses the long-term average.