{# ── Idle state ── #}
{% if scan_status == 'idle' %}
{# ── Error state ── #}
{% elif scan_status == 'error' %}
{# ── Sort-weight macros ── #}
{# Emit a numeric key used by data-order so DataTables sorts signals semantically #}
{% macro sig_w(v) -%}
{%- if v == 'STRONG BUY' -%}5
{%- elif v == 'BUY' -%}4
{%- elif v == 'NEUTRAL' -%}3
{%- elif v == 'WEAK - WAIT' -%}2
{%- elif v == 'SELL' -%}1
{%- else -%}0{%- endif -%}
{%- endmacro %}
{% macro trend_w(v) -%}
{%- if v == 'UPTREND' -%}3
{%- elif v == 'SIDEWAYS' -%}2
{%- elif v == 'DOWNTREND' -%}1
{%- else -%}0{%- endif -%}
{%- endmacro %}
{% macro cross_w(v) -%}
{%- if v == 'CROSS UP' -%}3
{%- elif v == 'NO CROSS' -%}2
{%- elif v == 'CROSS DOWN' -%}1
{%- else -%}0{%- endif -%}
{%- endmacro %}
{# Table #}
{% else %}
{# Done but zero results #}
{# /dashboardContent #}
🚀
{# ── Running state ── #}
{% elif scan_status == 'running' %}
No scan has been run yet
Configure your Finviz filters in the Controls tab, then click ▶ Run Scan.
Scan in progress…
Fetching data from Finviz · Yahoo Finance.
This can take a few minutes.
Elapsed: 0s
❌
{# ── Done state ── #}
{% elif scan_status == 'done' %}
{% if stocks %}
{# Stat cards #}
{% set ns = namespace(sb=0, sells=0, top=0) %}
{% for s in stocks %}
{% if s.TD_Signal == 'STRONG BUY' %}{% set ns.sb = ns.sb + 1 %}{% endif %}
{% if s.TD_Signal == 'SELL' %}{% set ns.sells = ns.sells + 1 %}{% endif %}
{% if s.Score is not none and s.Score|int > ns.top %}
{% set ns.top = s.Score|int %}{% endif %}
{% endfor %}
Scan failed
{{ scan_error }}
{{ stocks|length }}
Stocks Matched
{{ ns.sb }}
Strong Buy Signals
{{ ns.sells }}
Sell Signals
{{ ns.top }}
Top Score
📊 Stock Signals & Scores
{{ timestamp }}
| Source | Ticker | Price | Change % | Volume | RSI | ATR | TD Signal | TD Trend | YF Signal | EMA Cross | Score | Latest News | Insider Action |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| {{ s.Source }} | {# Ticker — sort alphabetically on raw ticker symbol #}{{ s.Ticker }} | {# Price — sort on raw float #}{{ '$' ~ "%.2f"|format(s.Price|float) if s.Price is not none else '—' }} | {# Change % — sort on raw float (preserves negative) #}{% if s.Change is not none %} {% set chg = s.Change|float %} {{ '+' if chg >= 0 else '' }}{{ "%.2f"|format(chg) }}% {% else %}—{% endif %} | {# Volume — sort on raw float (comma-formatted display) #}{{ "{:,.0f}".format(s.Volume|float) if s.Volume is not none else '—' }} | {# RSI — sort on raw float #}{% if s.RSI is not none %} {% set rsi = s.RSI|float %} {{ "%.1f"|format(rsi) }} {% else %}—{% endif %} | {# ATR — sort on raw float #}{{ "%.2f"|format(s.ATR|float) if s.ATR is not none else '—' }} | {# TD Signal — sort on semantic weight (STRONG BUY=5 … SELL=1) #} {% set sig = s.TD_Signal|string if s.TD_Signal is not none else '—' %}{% if sig == 'STRONG BUY' %} {{ sig }} {% elif sig == 'BUY' %}{{ sig }} {% elif sig == 'SELL' %}{{ sig }} {% elif sig == 'WEAK - WAIT' %} {{ sig }} {% elif sig == 'NEUTRAL' %} {{ sig }} {% else %}{{ sig }} {% endif %} | {# TD Trend — sort on semantic weight (UPTREND=3 … DOWNTREND=1) #} {% set tr = s.TD_Trend|string if s.TD_Trend is not none else '—' %}{% if tr == 'UPTREND' %}▲ {{ tr }} {% elif tr == 'DOWNTREND' %} ▼ {{ tr }} {% elif tr == 'SIDEWAYS' %} — {{ tr }} {% else %}{{ tr }} {% endif %} | {# YF Signal — sort on semantic weight #} {% set ys = s.YF_Signal|string if s.YF_Signal is not none else '—' %}{% if ys == 'STRONG BUY' %} {{ ys }} {% elif ys == 'BUY' %}{{ ys }} {% elif ys == 'SELL' %}{{ ys }} {% elif ys == 'WEAK - WAIT' %} {{ ys }} {% elif ys == 'NEUTRAL' %} {{ ys }} {% else %}{{ ys }} {% endif %} | {# EMA Cross — sort on semantic weight (CROSS UP=3, NO CROSS=2, CROSS DOWN=1) #} {% set xc = s.EMA_Cross|string if s.EMA_Cross is not none else '—' %}{% if xc == 'CROSS UP' %}↑ {{ xc }} {% elif xc == 'CROSS DOWN' %} ↓ {{ xc }} {% else %}{{ xc }} {% endif %} | {# Score — sort on raw int #}{% if s.Score is not none %} {% set sc = s.Score|int %} {{ sc }} {% else %}—{% endif %} | {# Latest News — plain text, no sort weirdness #}{{ s.Latest_News|string if s.Latest_News is not none else '—' }} | {# Insider Action — coerce to string first to avoid float-NaN 'in' crash #}{% set ia = s.Insider_Action|string if s.Insider_Action is not none else '—' %} {% if 'Buy' in ia %}🔼 {{ ia }} {% elif 'Sale' in ia or 'Sell' in ia %} 🔽 {{ ia }} {% else %} {{ ia }} {% endif %} |
🔍
{% endif %}
{% endif %}
No stocks matched your filters
Try loosening the filter criteria in Controls.
🔧 Scan Filters
These map directly to Finviz screener filter keys and values. Browse available filters ↗
{% for key, value in filters.items() %}
{% endfor %}
Background Scan Schedule (EST)
Scheduler checks every minute bucket and runs scans in the background based on this schedule. If an end time is earlier than its start time, that session continues past midnight into the next day.
Session
Start
End
Interval (min)
Enabled
After Hours
Run once daily
Valid only when run time is before close.
📨 Ticker Subscriptions
Click ↺ Refresh to load logs.