📈 EMA Z-Score Strategy & Backtest

NVDA EMA Z-Score
Trading Strategy

Mean-reversion strategy using Exponential Moving Average with adaptive variance & z-score signals. Trades every 10 seconds during market hours on NVDA.

Overview

This Python-based trading strategy uses an Exponential Moving Average (EMA) combined with an adaptive variance estimator to generate z-score signals. When the z-score exceeds the threshold, the strategy enters a mean-reversion trade — buying when price dips significantly below the EMA and selling when price spikes above it.

The strategy trades NVDA every 10 seconds during US market hours (9:30 AM – 4:00 PM ET), Monday through Friday, excluding market holidays. It uses the Alpaca IEX data feed for real-time quotes and paper trading for order execution.

Strategy Parameters

Symbol
NVDA
EMA Lambda (λ)
0.75
Z-Score Threshold
±2.0
Trade Quantity
25 shares
Long Limit
400 shares
Short Limit
-400 shares
Account Balance
$125,000
Trade Interval
10 sec
Var Price (seed)
0.001
Var Cap
100
Var Floor
0.05
Z Factor
1

Backtest Assumptions

  • Backtest start: January 2, 2026 (first trading day of 2026)
  • Backtest end: Most recent available data
  • Data source: Alpaca Data API, IEX feed, 1-minute bars (VWAP)
  • Trade frequency: Every 1-minute bar (approximates 10-second live intervals)
  • Order type: Market orders, filled at VWAP of bar
  • Position limits: Max +400 shares long, -400 shares short
  • Market hours: 9:30 AM – 4:00 PM ET, M–F, excluding NYSE holidays
  • Starting balance: $125,000
  • Commissions: $0 (commission-free via Alpaca)
  • Slippage: Not modeled (filled at VWAP)

📊 Performance Analysis

Backtest results from backtest_ema_nvda.py. Run the script to generate or update results.

Daily P&L Progression

Daily Breakdown

Date Open Close High Low Trades Position Total P&L

Recent Trades

Timestamp Side Qty Price Position After Realized P&L

How It Works

📐 EMA Calculation

The Exponential Moving Average uses λ=0.75 decay: EMA = λ × prev_EMA + (1-λ) × price. This gives recent prices 25% weight each tick, creating a responsive but smooth signal.

📊 Adaptive Variance

Variance is estimated using EWMA: σ² = λ × prev_σ² + (1-λ) × (price - EMA)², clamped between floor (0.05) and cap (100). This adapts to changing volatility regimes.

⚡ Z-Score Signal

The z-score is computed as z = (price - EMA) / √σ². When |z| exceeds 2.0, a trade signal fires — buy when z < -2.0 (price below EMA), sell when z > 2.0 (price above EMA).

🛡️ Risk Controls

Position limits enforce max 400 shares long or short. Trade size is 25 shares per signal. The strategy respects market hours and holidays automatically.

Python Trading Script

The live trading script. Run with python ema_nvda_trader.py or python ema_nvda_trader.py --dry-run for simulation.

ema_nvda_trader.py
Loading...

Backtest Script

Run with python backtest_ema_nvda.py to generate ema_nvda_backtest_results.json.

backtest_ema_nvda.py
Loading...

Customization Options

Easily modify the strategy parameters at the top of ema_nvda_trader.py:

🎯 Change Symbol

Update SYMBOL = "NVDA" to any Alpaca-supported ticker to trade a different stock.

⚙️ Tune EMA Sensitivity

Adjust LAMBDA_F (0→1): lower values make the EMA more responsive to recent prices; higher values smooth more.

📏 Adjust Z-Score Threshold

Raise Z_SCORE_THRESH for fewer, higher-conviction trades. Lower it for more frequent signals.

📊 Position Sizing

Change TRADE_QTY, LIMIT_LONG, and LIMIT_SHORT to control trade size and max exposure.

Ready to Run This Strategy?

Deploy the NVDA EMA z-score strategy on your MachineTrader™ instance with paper or live trading.