[object Object]

← 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

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 →