Skip to content

FloofyJin/MarketStrategies

Repository files navigation

Trading Analyzer

A research framework for discovering, combining, and backtesting algorithmic trading strategies on BTC price data. The project explores whether classical technical signals — individually weak — can be made profitable through regime filtering, multi-signal confluence scoring, and mathematically-grounded position sizing.

What it does

Rather than implementing a single strategy, this project is a systematic search for edge:

  1. Generate signals from a library of independent technical strategies
  2. Detect the market regime (trending vs. ranging vs. noise) to know which signals apply
  3. Combine signals via weighted confluence scoring — only trade when multiple strategies agree
  4. Size positions using Kelly Criterion based on empirical win rates
  5. Backtest everything on historical 1-minute BTC data with realistic fees (0.05% per side), then validate out-of-sample

The best result found: +0.61% net return during BTC's 2022 bear market (when BTC itself fell ~55%), with a 62% win rate and -0.82% max drawdown over 82 trades across 15.5 months.


Project Structure

signals.py            — Core signal library (6 classic strategies + OHLCV resampler)
advanced_signals.py   — Extended signals (VWAP, Kalman, ATR z-score, LinReg Channel, etc.)
backtest.py           — Backtest engine with realistic execution (entry at next open, worst-case stop fills)
strategy_engine.py    — Full integrated pipeline (regime → confluence → Kelly → backtest)
regime.py             — Market regime classifier (ADX + Efficiency Ratio + Hurst Exponent)
regime_calibrator.py  — BTC-specific regime threshold calibration
ou_analysis.py        — Ornstein-Uhlenbeck fitting to derive optimal hold periods and stop placement
confluence.py         — Weighted multi-strategy confluence combinations
ml_filter.py          — Random Forest classifier to filter trade entries by predicted win probability
signal_analysis.py    — Bar-by-bar signal matrix and forward return analysis
tuner.py              — Per-strategy grid search over parameters
momentum_tuner.py     — Joint ROC + intraday momentum parameter grid search
leverage_sweep.py     — Sweep over leverage levels to find risk-adjusted optimum
zscore_sweep.py       — Sweep over z-score entry thresholds
yearly_analysis.py    — Year-by-year performance breakdown
dataset/              — BTC 1-minute OHLCV data (2012–present, ~600k rows)
results/              — Output CSVs, parquets, and history files
logs/                 — findings.md (research notes), ideas.md (open questions)

Signal Library

Classic signals (signals.py)

Signal Logic
MA Crossover Fast EMA crosses above/below slow EMA
Bollinger Bands Price crosses outside 2σ band
Mean Reversion Rolling z-score > threshold → fade the move
Momentum (ROC) Rate-of-change exceeds threshold → follow momentum
Breakout Price breaks N-bar high/low on elevated volume
Intraday Momentum NYSE open momentum (14:30 UTC trigger)

Advanced signals (advanced_signals.py)

Signal Logic
LinReg Channel OLS trend z-score of residuals — avoids drift in rolling mean
VWAP Reversion Fade moves far from daily VWAP
Kalman Z-score Kalman-filtered price vs. raw price spread
ATR Z-score Normalize price deviation by ATR (volatility-adjusted)
Volume Oscillator Short/long volume MA ratio to confirm signal quality
Macro Trend Filter 200-day EMA gate to block longs in bear markets

The Pipeline (strategy_engine.py)

1-min data
    │
    ▼
5-min OHLCV resample      ← reduces noise; fees now ~15% of expected move vs. 33% at 1-min
    │
    ▼
Regime detection           ← ADX + Efficiency Ratio + Hurst Exponent (majority vote)
    │
    ├─ TREND  → activate momentum/breakout signals (2× weight)
    ├─ RANGE  → activate mean-reversion/VWAP/Kalman signals (2× weight)
    └─ NEUTRAL → no trades (empirically 24–33% win rate — pure noise)
    │
    ▼
Confluence score ≥ 2       ← blocks ~95% of signals; only highest-conviction setups
    │
    ▼
ML filter (optional)       ← Random Forest P(win) ≥ 0.55 gate
    │
    ▼
ATR-based dynamic stop     ← 2.0× ATR for RANGE, 1.5× ATR for TREND
    │
    ▼
OU-derived hold period     ← 1.5× mean-reversion half-life (~75 min on 5-min BTC)
    │
    ▼
Kelly position sizing      ← half-Kelly (f*/2) to reduce drawdown
    │
    ▼
Backtest (3 modes)
    A. Naive — no regime filter, equal weights, fixed params
    B. Regime-gated — regime + ATR stops, no Kelly
    C. Full engine — all of the above + Kelly sizing

Regime Detection (regime.py)

Three independent measures vote on each bar:

  • ADX — trend strength (higher = stronger trend regardless of direction)
  • Efficiency Ratio|net move| / Σ|individual moves| → 1.0 = clean trend, 0.0 = chop
  • Hurst Exponent — H > 0.5 = trending, H < 0.5 = mean-reverting, H ≈ 0.5 = random walk

BTC distribution on 5-min bars: ~50% RANGE, ~45% NEUTRAL, ~5% TREND. The TREND regime has historically shown only 9–10% win rate at 1-min resolution and is disabled for trading.


Ornstein-Uhlenbeck Analysis (ou_analysis.py)

Fits the OU process dX = θ(μ - X)dt + σdW to price data via OLS regression to derive:

  • Half-life = ln(2)/θ → how long before a deviation decays 50% back to mean
  • Optimal hold period ≈ 1–2× half-life
  • Stop placement ≈ 2–3× σ from entry

On 5-min BTC: half-life ≈ 10 bars (50 min) → hold ≈ 15 bars (75 min).


ML Filter (ml_filter.py)

A Random Forest classifier trained on potential entry bars (from the training set) that predicts whether a trade will be profitable. Features include all signal values, ATR, volume ratio, price momentum at multiple lookbacks, cyclical time-of-day and day-of-week encodings, regime encoding, and z-score magnitude.

Uses shallow trees (max_depth=4, min_samples_leaf=8) and out-of-bag scoring to control overfitting — sample sizes are small (~100–500 entries per training period).


Key Config

All global parameters live at the top of signals.py:

FEES        = 0.0005        # 0.05% per side
DATA_PATH   = "dataset/btc_1-min_data.csv"
START_DATE  = "2016-01-01"
END_DATE    = "2026-03-29"
TRAIN_SPLIT = 0.80          # 80% in-sample, 20% out-of-sample

Strategy parameters in strategy_engine.py under TIMEFRAME_CONFIGS.


Running

# Set up environment
python3.12 -m venv venv
venv/bin/pip install pandas numpy pyarrow scikit-learn

# Run the full strategy engine (all 3 modes on train + test)
venv/bin/python3.12 strategy_engine.py

# Sanity-check advanced signals
venv/bin/python3.12 advanced_signals.py

# Grid search a single strategy's parameters
venv/bin/python3.12 tuner.py

# Sweep z-score thresholds
venv/bin/python3.12 zscore_sweep.py

# Year-by-year breakdown
venv/bin/python3.12 yearly_analysis.py

Results are written to results/ as CSV/parquet. Research notes accumulate in logs/findings.md.


Data

dataset/btc_1-min_data.csv — BTC/USD 1-minute OHLCV from 2012 to present (~600k rows).

Columns: Timestamp (Unix), Open, High, Low, Close, Volume

Data is loaded in chunks (50k rows at a time) and filtered to the configured date range to avoid loading the full file into memory.


Key Findings

  • 1-min BTC is fundamentally mean-reverting: ~53% of bars are in RANGE regime; TREND only 3–5%.
  • Fees kill 1-min signals: at 1-min, fees consume ~33% of expected move; at 5-min this drops to ~15%.
  • Mean Reversion and Bollinger Bands produce identical signals at current parameters — never use both.
  • Dual confirmation blocks 95% of trades but keeps only the highest-conviction setups with 57–58% win rate.
  • The 200-day EMA macro filter is critical: during the 2022 bear market, it blocked longs entirely, reducing losing long trades from 84 to 13.
  • LinReg Channel is cleaner than rolling mean z-score: rolling mean drifts with price in trends, creating false normalizations; OLS regression accounts for the trend direction.
  • Kelly (half) reduces drawdown significantly on training data (-5% → -0.36%) at the cost of lower upside.

Open Questions

  • Dynamic stop/target: scale stop size with volatility (ATR-based), or place stop just below previous local minimum in a zig-zag pattern.
  • Confidence-based position sizing: allocate 10% of capital when uncertain, up to 70% when highly confident — beyond fixed Kelly.
  • Neural network entry filter: train a model on all strategy outputs simultaneously to find patterns that rule-based confluence misses.

About

No description, website, or topics provided.

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages