Skip to content

Repository files navigation

turtle

A modernized web app for experimenting with the vanilla Richard Dennis turtle trading strategy.

This version uses server-side historical EOD data lookup, a simplified strategy engine, and a lightweight browser UI for ticker selection and backtesting.

Research status and warning

This repository is a research artifact, not a live trading system.

After a series of realism checks, benchmark comparisons, broader universe tests, relative-strength filters, and hybrid SPY-core experiments, the current conclusion is that these Turtle-inspired long-only equity variants are not compelling enough to use as a replacement for passive index investing.

The project found some interesting behavior, especially around relative-strength filters and passive-core/active-sleeve hybrids, but the remaining edge was small, regime-dependent, and likely not large enough to overcome taxes, slippage, operational burden, overfitting risk, and ordinary benchmark alternatives such as SPY and QQQ.

If you found this repo while looking for a trading strategy to run with real money, start with the closing note:

The short version:

Backtests can be useful, but a strategy that only barely beats a simple benchmark in selected tests has not earned live-capital confidence.

Quick start

  1. Install dependencies:
npm install
  1. Run the app:
npm start
  1. Open http://localhost:3000

Requires Node.js 24 or newer.

Market data cache

Yahoo historical chart responses are cached on disk in .cache/market-data for 24 hours by default. You can tune this with:

MARKET_DATA_CACHE=false
MARKET_DATA_CACHE_DIR=.cache/market-data
MARKET_DATA_CACHE_TTL_HOURS=24

Matrix runner

Run ticker/date-range batches from the command line and write results to CSV:

npm run matrix

By default this runs the built-in 18-symbol by 4-date-range matrix and writes to reports/matrix-results-*.csv. Useful smaller runs:

npm run matrix -- --dry-run
npm run matrix -- --limit=3
npm run matrix -- --symbols=AAPL,SPY --ranges=2020-01-01:2024-12-31

Universe files

Portfolio and benchmark runners can load symbols from a text file with --symbolsFile. Files may use commas, spaces, or newlines, and # starts a comment:

npm run portfolio -- --symbolsFile=universes/sector-etfs.txt --gapAwareFills=true --maxUnits=1 --slippageBps=5
npm run benchmarks -- --symbolsFile=universes/sector-etfs.txt --benchmarkSymbols=SPY,QQQ,IWM,DIA

Portfolio runs can also sweep same-day entry ordering with --entryRank. Supported values are alphabetical, momentum63, and momentum126:

npm run portfolio -- --symbolsFile=universes/sp500-top100-established.txt --gapAwareFills=true --maxUnits=1 --slippageBps=5 --entryRank=alphabetical,momentum63,momentum126

Risk sizing can be swept with comma-separated --riskPercent values:

npm run portfolio -- --symbolsFile=universes/sp500-top100-established.txt --gapAwareFills=true --maxUnits=1 --slippageBps=5 --entryRank=momentum126 --riskPercent=0.25,0.5,1

Concurrent position limits can be swept with comma-separated --maxOpenPositions values:

npm run portfolio -- --symbolsFile=universes/sp500-top100-established.txt --gapAwareFills=true --maxUnits=1 --slippageBps=5 --entryRank=momentum126 --riskPercent=0.25 --maxOpenPositions=10,20,30

Market regime filters can gate new entries and add-ons with a broad-market moving average. Use --marketRegimeMa=0,200 to compare the unfiltered strategy with a prior-close SPY 200-day SMA filter:

npm run portfolio -- --symbolsFile=universes/sp500-top100-established.txt --gapAwareFills=true --slippageBps=5 --entryRank=momentum126 --riskPercent=0.25 --entryPeriod=55 --exitPeriod=50 --maxUnits=1,2,4 --marketRegimeSymbol=SPY --marketRegimeMa=0,200

Relative-strength filters can require breakout candidates to outperform a benchmark over a prior return lookback. Use --relativeStrengthLookback=0,126 to compare unfiltered entries with entries that have beaten SPY over the prior 126 trading days:

npm run portfolio -- --symbolsFile=universes/sp500-top100-established.txt --gapAwareFills=true --slippageBps=5 --entryRank=momentum126 --riskPercent=0.25 --entryPeriod=55 --exitPeriod=50 --maxUnits=1,2,4 --relativeStrengthSymbol=SPY --relativeStrengthLookback=0,126

Hybrid runs combine a passive buy-and-hold core with an active trend-following sleeve. Use --activeAllocationPct to sweep the active sleeve size; the remaining allocation goes to --coreSymbol. Use --rebalance=none,annual,quarterly to compare initial-allocation-only hybrids with periodic target-weight rebalancing:

npm run hybrid -- --symbolsFile=universes/sp500-top100-established.txt --coreSymbol=SPY --activeAllocationPct=20,30 --rebalance=none,annual,quarterly --gapAwareFills=true --slippageBps=5 --entryRank=momentum126 --riskPercent=0.25 --entryPeriod=55 --exitPeriod=50 --maxUnits=1 --maxOpenPositions=10 --relativeStrengthSymbol=SPY --relativeStrengthLookback=63,84

About

A web app to implement some of the basic decision metrics and algorithms used in the "turtle trading" strategy created by Richard Dennis.

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages