• AWK + S&P 500 + Buying The Dip

    From Mike Sanders@porkchop@invalid.foo to comp.lang.awk on Thu Sep 25 14:25:20 2025
    From Newsgroup: comp.lang.awk

    Hi folks, hope everyone is doing well.

    Another experiment to mull over (notes below).
    Very useful script for me at least. Hope it
    posts without wordwrap (trying out 'Pan'
    newsreader for the 1st time).

    Must run, lots of irons in the fire these days...
    Hope to check in with you guys down the road,
    learn some new things.

    Work hard & make your mother proud!

    #!/bin/sh

    :<<'ABOUT'

    Michael Sanders - 2025

    'Buying the dip' is an investment strategy where an investor purchases assets after their price has dropped, with the expectation that the value will rebound. The tactic is an application of the basic principle, 'buy low, sell high'.

    This script fetches historical data within the specified range for the S&P 500 & determines if the price is down slightly within a broader upward trend. The result is that you'll save a nickel or two on the price. The rationale here is that, while its great to have cash on the side ready to invest, if a strong pullback in the market doesn't happen very frequently, then your cash misses out on potential gains...

    Some popular ETFs that track the SPX index include:

    VOO: Vanguard S&P 500
    SPY: SPDR S&P 500
    SPLG: SPDR Portfolio S&P 500
    IVV: iShares Core S&P 500

    FORMULA:

    BUF IF SPX < SMA10 AND SPX > SMA30 AND RSI14 > 39 AND RSI14 < 51 ELSE WAIT

    Condition Meaning

    SPX < SMA10 Short-term pullback from recent highs
    SPX > SMA30 Still trending upwards overall
    RSI14 > 39 AND RSI14 < 51 Momentum is mild indicating healthy consolidation BUY / WAIT Buy if all conditions are true, otherwise wait

    GLOSSARY:

    SPX: S&P 500 index, representing the overall U.S. large-cap market.

    SMA10: 10-day Simple Moving Average, average closing price over the last
    10 trading days.

    SMA30 30-day Simple Moving Average, average closing price over the last
    30 trading days.

    RSI14: 14-day Relative Strength Index, momentum indicator measuring
    overbought/oversold conditions.

    ABOUT

    S=$(date -d "45 days ago" +%Y-%m-%d) # start date
    E=$(date +%Y-%m-%d) # end date

    URL="https://fred.stlouisfed.org/graph/fredgraph.csv?id=SP500&cosd=$S&coed=$E"

    curl -Ls "$URL" | awk -v mini=0 '

    BEGIN { OFS = FS = "," }

    # round to n decimals: 2.344 = 2.34, 2.345 = 2.35
    function round(x, dec) {
    factor = 10^dec
    return int(x * factor + 0.5) / factor
    }

    # simple moving average
    function SMA(len, i,sum) {
    if (n < len) return ""
    sum = 0
    for(i = n - len + 1; i <= n; i++) sum += closes[i]
    return sum / len
    }

    # relative strength index
    function RSI(len, i,gain,loss,diff,rs) {
    if (n <= len) return ""
    gain = loss = 0
    for(i = n - len + 1; i <= n; i++) {
    diff = closes[i] - closes[i-1]
    if (diff > 0) gain += diff
    else loss -= diff
    }
    if (loss == 0) return 100
    rs = gain / loss
    return 100 - (100 / (1 + rs))
    }

    NR==1 { next } # skip CSV header

    {
    gsub(/"/,"",$2) # remove quotes from the CLOSE field

    if ($2 ~ /^[0-9.]+$/) {
    n++
    closes[n] = $2 * 1 # convert string to number
    dates[n] = $1 # store corresponding date
    }

    }

    END {
    if (n < 1) { print "No valid data"; exit }
    last = closes[n]

    sma10 = (n >= 10 ? SMA(10) : "")
    sma30 = (n >= 30 ? SMA(30) : "")
    rsi14 = (n >= 15 ? RSI(14) : "")

    # buy/wait signal (no rounding here use full precision)
    signal = "WAIT"
    if (sma10 != "" && sma30 != "" && rsi14 != "") {
    if (last < sma10 && last > sma30 && rsi14 > 39 && rsi14 < 51) signal="BUY"
    }

    # check if any computed field is missing or non-numeric
    invalid = (sma10 == "" || sma30 == "" || rsi14 == "" || last == "")

    # minimal output only...
    if (mini) {
    print dates[n] " SPX " (invalid ? "ERROR" : signal)
    exit
    }

    # print header
    print "DATE,INDEX,CLOSE,SMA10,SMA30,RSI14,SIGNAL"

    # print last row (current day) directly with rounding expressions
    if (invalid) {
    print dates[n], "SPX", "", "", "", "", "", "ERROR"
    } else {
    print dates[n], "SPX",
    round(last, 2),
    round(sma10, 2),
    round(sma30, 2),
    round(rsi14, 1),
    signal
    }
    }'

    # eof
    --- Synchronet 3.21a-Linux NewsLink 1.2