# entry: all 5 conditions true on the same 15m candle
Daily EMA(20) > Daily EMA(50)
Price > Daily SMA(200)
4H EMA(20) > 4H EMA(50) # plain UTC-floor 4h blocks
1H RSI(14) < 45
15m close > entire previous 15m candle's high
# exit
15m RSI(14) >= 80 # no stop-loss, no time limit, held until target or data ends
Data Sourcing
Daily: 2 years. 1H: ~700 days. 15m: 60 days (yfinance's hard retention limit for that granularity — this is the real ceiling on sample size, not a choice). All three pulled with fixed start/end dates, not a rolling period=Nd window — the first version of this backtest used a rolling window and gave different results on every re-run as "now" shifted; fixed dates made it fully reproducible (confirmed identical across 3 independent re-runs before trusting any number).
Bad-Tick Filtering
Any single trade with |return| > 30% is excluded before scoring, not included and caveated. Thin-liquidity altcoins' intraday yfinance data has occasional one-bar glitches — one early run showed a 15m trade returning +169% in 4 hours, which isn't real price action. 6 trades were excluded this way out of several hundred found.
✓ Pass 1 — 10 major pairs (BTC, ETH, SOL, BNB, XRP, ADA, DOGE, AVAX, LINK, DOT). First signal check: 55 resolved trades, 67.3% win, +1.40% avg, PF 2.87 — comparable to the equities rule, worth expanding.
! Pass 2 — expanded to 93 pairs, rolling download window. Results were wildly inconsistent between runs on identical pairs (0 entries → 7 entries → different numbers again) — not real signal, a data-fetch artifact from the rolling period=60d window shifting on every call.
✓ Pass 3 — fixed dates + bad-tick exclusion. Deterministic and stable across repeated runs against that self-compiled 93-pair list.
✓ Pass 4 — switched to the real source. Pulled Robinhood's actual tradable-crypto list directly from its public nummus.robinhood.com/currency_pairs/ endpoint (no credentials needed) instead of a self-compiled guess: 90 pairs, 88 after excluding 2 stablecoins. Filtered to market cap >= $100M (55 pairs), then cross-checked each against Alpaca's actual GET /v2/assets?asset_class=crypto listing — only 25 of the 55 are tradable there. These are the numbers below.
All 55 pairs combined
25 live-tradable (Alpaca) pairs — this account's actual universe
30 signal-only (Robinhood, not Alpaca) pairs — display only, never auto-traded
Reported plainly rather than cherry-picked: the 30 pairs Alpaca doesn't carry actually backtest a bit
better than the 25 it does (80.7% vs 69.2% win rate, +4.08% vs +2.87% avg). That's worth knowing if
you're deciding whether to act on a signal-only pair's buy/sell flag manually on Robinhood — see Trade Crypto
for the live condition breakdown on all 55, including a dedicated manual-reference column.
| Pair | Trades | Win Rate | Avg Return | Profit Factor |
| RAY-USD | 10 | 90.0% | +9.55% | 30.02 |
| ONDO-USD live | 3 | 66.7% | +8.08% | 13.65 |
| ENA-USD | 5 | 100.0% | +7.29% | ∞ |
| WIF-USD live | 8 | 87.5% | +6.87% | 10.12 |
| SYRUP-USD | 4 | 100.0% | +6.79% | ∞ |
| XLM-USD | 5 | 100.0% | +5.62% | ∞ |
| MORPHO-USD | 5 | 80.0% | +5.31% | 33.10 |
| LTC-USD live | 4 | 100.0% | +5.00% | ∞ |
| NEAR-USD | 4 | 75.0% | +4.61% | 6.96 |
| PYTH-USD | 6 | 83.3% | +4.52% | 14.98 |
| LDO-USD live | 6 | 66.7% | +4.45% | 4.57 |
| ZEC-USD | 10 | 80.0% | +4.37% | 6.28 |
| UNI-USD live | 8 | 62.5% | +4.01% | 2.34 |
| ZRX-USD | 6 | 83.3% | +3.60% | 3931.73 |
| EIGEN-USD | 3 | 100.0% | +3.07% | ∞ |
| AAVE-USD live | 8 | 75.0% | +3.06% | 3.66 |
| WLD-USD | 8 | 87.5% | +2.98% | 2.91 |
| LINK-USD live | 10 | 80.0% | +2.71% | 3.90 |
| SOL-USD live | 10 | 70.0% | +2.30% | 15.42 |
| ETH-USD live | 9 | 77.8% | +2.19% | 9.55 |
| GRAM-USD | 5 | 60.0% | +1.62% | 2.14 |
| CRV-USD live | 5 | 60.0% | +1.38% | 1.59 |
| ORCA-USD | 4 | 75.0% | +1.30% | 9.34 |
| BNB-USD | 3 | 100.0% | +1.15% | ∞ |
| VIRTUAL-USD | 5 | 40.0% | +1.08% | 1.32 |
| BTC-USD live | 6 | 66.7% | +0.82% | 1.83 |
| XRP-USD live | 6 | 50.0% | +0.69% | 1.74 |
| PEPE-USD live | 5 | 40.0% | -0.51% | 0.73 |
| ADA-USD live | 4 | 50.0% | -1.05% | 0.27 |
| DOGE-USD live | 3 | 33.3% | -1.80% | 0.38 |
| INJ-USD | 6 | 33.3% | -3.04% | 0.27 |
24 more pairs (of 55) had 1-2 trades or none at all in the 60-day window — too few to rank, not shown.
✓ Broker constraint, not a curation choice. 55 pairs clear the $100M market-cap bar; only 25 of those are tradable on Alpaca at all (checked directly against its asset list, not assumed). The other 30 simply can't be auto-traded here regardless of how well they backtest.
! Not the better-performing half. The 25 live pairs actually backtest slightly worse than the 30 signal-only pairs (69.2% vs 80.7% win, +2.87% vs +4.08% avg) — reported plainly, not hidden. If you want the stronger-looking names, several of them (RAY, ENA, SYRUP, XLM, MORPHO, NEAR, PYTH, ZEC) are in the signal-only tier and only tradable manually on Robinhood.
✓ $100M floor still applies to both tiers. Neither list includes the smallest/newest tokens that produced some of the flashiest-looking small-sample numbers in earlier passes.
! 60-day window only — yfinance's hard retention limit for 15-minute data. This is a first signal, not a validated long-run edge.
! Backtest ≠ live. This is a candle-by-candle replay against historical data, not a record of trades actually taken. The live account's own trade history (visible on Crypto Account) is the real test for the 25 live pairs; for the 30 signal-only pairs, any real test happens on whatever account you manually trade them from.
✓ Revisit plan: once enough live paper-trade history has accumulated, re-run this exact methodology against the live trade log the same way BO15's equities rule was re-tested against its own real trades (see Workflow).