← back to Stock Vshape Viewer
10 preloaded strategy presets (one-click screens: Deep V-Recovery, 50/200-DMA pullbacks, breakouts, bottom-fishing, etc.)
d409d10c35e13fa10b69701887e568fba410c679 · 2026-08-27 11:20:03 -0700 · Steve
Files touched
M public/app.jsM public/data.jsM public/index.html
Diff
commit d409d10c35e13fa10b69701887e568fba410c679
Author: Steve <steve@designerwallcoverings.com>
Date: Thu Aug 27 11:20:03 2026 -0700
10 preloaded strategy presets (one-click screens: Deep V-Recovery, 50/200-DMA pullbacks, breakouts, bottom-fishing, etc.)
---
public/app.js | 20 ++++++++++++++++++--
public/data.js | 24 ++++++++++++++++++++++++
public/index.html | 11 +++++++++++
3 files changed, 53 insertions(+), 2 deletions(-)
diff --git a/public/app.js b/public/app.js
index 2e14bbb..e225fdd 100644
--- a/public/app.js
+++ b/public/app.js
@@ -448,10 +448,26 @@ function loadSaved(s) {
state.tfN = s.tfN || 126;
if (s.tickers && s.tickers.length) state.tickers = [...s.tickers];
save(LS.filters, state.filters); save(LS.tf, state.tfN); save(LS.tickers, state.tickers);
- syncFilterUI();
+ syncFilterUI(); syncOptUI();
loadAll(); // re-fetch (ticker set may differ)
}
+// preset strategies — one-click screens
+function renderPresets() {
+ const el = document.getElementById('presets');
+ el.innerHTML = window.PRESETS.map((p, i) =>
+ `<div class="p" data-i="${i}" title="${p.desc}"><div class="pn">${p.name}</div><div class="pd">${p.desc}</div></div>`).join('');
+ el.querySelectorAll('.p').forEach(row => row.onclick = () => applyPreset(+row.dataset.i));
+}
+function applyPreset(i) {
+ const p = window.PRESETS[i];
+ state.filters = Object.assign({}, window.DEFAULT_FILTERS, state.filters ? { optMin: state.filters.optMin, optMax: state.filters.optMax, optMinMonths: state.filters.optMinMonths, optType: state.filters.optType } : {}, p.filters);
+ state.tfN = p.tfN || 126;
+ save(LS.filters, state.filters); save(LS.tf, state.tfN);
+ document.querySelectorAll('#presets .p').forEach((el, k) => el.classList.toggle('on', k === i));
+ syncFilterUI(); syncOptUI(); updateCriteriaChips(); process();
+}
+
// ============================ filter UI wiring ============================
const SLIDERS = [
['weeksAgo', 'f-weeksAgo', 'v-weeksAgo', v => `${v} wks`, true],
@@ -663,7 +679,7 @@ function syncOptUI() {
}
// ============================ boot + loop ============================
-syncFilterUI(); syncOptUI(); wireFilters(); wireScanAndOptions(); wireBrush(); renderSaved(); updateCriteriaChips();
+syncFilterUI(); syncOptUI(); wireFilters(); wireScanAndOptions(); wireBrush(); renderSaved(); renderPresets(); updateCriteriaChips();
loadAll();
let t0 = performance.now();
diff --git a/public/data.js b/public/data.js
index 215bf45..5aefc7c 100644
--- a/public/data.js
+++ b/public/data.js
@@ -18,6 +18,30 @@ window.DEFAULT_FILTERS = {
optMin: 0.05, optMax: 0.15, optMinMonths: 3, optType: 'both',
};
+// 10 preloaded strategy presets — one-click screens. Each sets the filters + timeframe.
+window.PRESETS = [
+ { name: 'Deep V-Recovery', desc: 'Deep 20%+ correction fully reclaimed to a new high (MRNA-style).',
+ tfN: 252, filters: { minDip: 20, reqNewHigh: true, weeksAgo: 8, weeksTol: 5, maxFromHigh: 15 } },
+ { name: 'Classic V (10% dip)', desc: 'The core screen — ~6-week-old high, 10% dip, fresh new high.',
+ tfN: 126, filters: { minDip: 10, reqNewHigh: true, weeksAgo: 6, weeksTol: 3, maxFromHigh: 60 } },
+ { name: '50-DMA Pullback Buy', desc: 'Uptrend pulling back to touch the 50-day — buy-the-dip setup.',
+ tfN: 126, filters: { minDip: 5, reqNewHigh: false, dipTo50: true, maxFromHigh: 20 } },
+ { name: '200-DMA Deep Value', desc: 'Testing the 200-day average — deep-value entry zone.',
+ tfN: 252, filters: { minDip: 15, dipTo200: true, reqNewHigh: false, maxFromHigh: 35 } },
+ { name: 'Fresh Breakout', desc: 'At new highs right now (within 3% of its recent high).',
+ tfN: 126, filters: { minDip: 8, reqNewHigh: true, maxFromHigh: 3, weeksAgo: 6 } },
+ { name: 'Below 50 — Reversal Watch', desc: 'Broke under the 50-day after a 12%+ dip — watch for a turn.',
+ tfN: 126, filters: { minDip: 12, below50: true, reqNewHigh: false, maxFromHigh: 40 } },
+ { name: 'Momentum Leaders', desc: 'Strong names hugging their highs (shallow dip, close to high).',
+ tfN: 63, filters: { minDip: 5, reqNewHigh: true, maxFromHigh: 6, weeksAgo: 4, weeksTol: 2 } },
+ { name: 'Big-Dip Bottom Fishing', desc: 'Down 25%+ and not recovered yet — deep-dip candidates.',
+ tfN: 252, filters: { minDip: 25, reqNewHigh: false, maxFromHigh: 60 } },
+ { name: 'Coiled Consolidation', desc: 'Recent high, shallow pullback, tightening — pre-breakout coil.',
+ tfN: 63, filters: { minDip: 8, maxFromHigh: 8, weeksAgo: 4, weeksTol: 2, reqNewHigh: false } },
+ { name: 'Yearly Base Reversal', desc: '2-year base, deep dip, currently under the 200-day.',
+ tfN: 504, filters: { minDip: 20, dipTo200: true, below200: true, reqNewHigh: false } },
+];
+
// bridge the shared engine so existing calls (window.sma / window.analyze) work
window.sma = window.SCREEN.sma;
window.analyze = window.SCREEN.analyze;
diff --git a/public/index.html b/public/index.html
index a783e13..e5e5b06 100644
--- a/public/index.html
+++ b/public/index.html
@@ -127,6 +127,12 @@
#d-brush{width:100%;height:38px;display:block;cursor:ew-resize;border:1px solid var(--stroke);border-radius:6px;background:#0a1120}
.brushhint{font-size:9.5px;color:#5c6f92;margin-top:2px;text-align:center}
.results .r .optbadge{font-size:10px;font-weight:700;padding:1px 5px;border-radius:5px;min-width:18px;text-align:center}
+ .presets{display:flex;flex-direction:column;gap:4px}
+ .presets .p{padding:7px 9px;border-radius:8px;background:rgba(255,255,255,.03);cursor:pointer;border:1px solid transparent}
+ .presets .p:hover{background:rgba(87,140,255,.12);border-color:#2f4d8f}
+ .presets .p.on{background:rgba(87,140,255,.16);border-color:#4a6bb5}
+ .presets .p .pn{font-size:12px;font-weight:600}
+ .presets .p .pd{font-size:10px;color:var(--dim);margin-top:1px}
#vchart{width:100%;height:56px;display:block;margin-top:3px}
.malegend{display:flex;gap:12px;font-size:10.5px;color:var(--dim);margin:6px 0}
.malegend i{display:inline-block;width:14px;height:2px;vertical-align:middle;margin-right:4px}
@@ -170,6 +176,11 @@
<div class="results" id="scan-results"></div>
</div>
+ <div class="sec">
+ <h3>Preset strategies</h3>
+ <div class="presets" id="presets"></div>
+ </div>
+
<div class="sec">
<h3>Watchlist · add a stock</h3>
<div class="addrow">
← 2c3a2dc Volume profile (shares-at-price / POC + value area), OBV vol
·
back to Stock Vshape Viewer
·
Include ETFs in scan (48 major ETFs: SPY/QQQ/sector SPDRs/AR 27672c8 →