A small “entry-point” repo that hosts my Python finance utilities and shared helpers used across my other projects.
Right now, the main utility here is Swing Tickers (Universe Builder): it takes a raw universe of Canadian tickers and filters/ranks the ones that look suitable for 1–3 week swing trading, using daily data from Yahoo Finance via yfinance.
Disclaimer: This is not financial advice. It’s a screening/ranking tool, not a trading system.
.
├─ data/
│ └─ can_tickers # one ticker per line (Yahoo format: .TO/.V/.CN/...)
├─ py/
│ └─ swing_tickers.py # universe builder / screener
│ └─ tickers_info.py # ticker metadata/market info builder
├─ requirements.txt
└─ README.md
- Python 3.10+ recommended
- Packages:
yfinancepandasnumpy
Install:
python -m venv .venv
source .venv/bin/activate # (Linux/macOS)
pip install -r requirements.txtGiven a text file of tickers (one per line), it downloads daily OHLCV history and computes a set of liquidity + volatility + trend/RS checks. It then outputs:
- Tradable tickers (newline-separated) — good for feeding into other scanners/tools
- Tradable tickers (comma-separated) — one-line format (handy for quick copy/paste)
- Rejected tickers CSV — includes rejection reasons for diagnostics
- One ticker per line
- Yahoo symbols (for Canada commonly:
.TO,.V,.CN, sometimes.NE, etc.) - Example:
BCE.TO
ENB.TO
CVE.TO
SHOP.TO
Repo already includes a universe file at:
data/can_tickers
Run it from root.
python swing_tickers.pyIt will write to:
out/can_tickers_swing(newline-separated tickers)out/can_tickers_swing_one_line(comma-separated tickers)out/can_tickers_rejected.csv(rejected tickers + reasons)
It will also print:
- counts (tradable/rejected/total)
- Top 20 tradable with key metrics
- a rejection reason breakdown
from swing_tickers import UniverseBuilderConfig, Thresholds, run_universe_builder
cfg = UniverseBuilderConfig(
tickers_path="../data/can_tickers",
benchmark="XIU.TO",
out_file_path="../out/can_tickers_swing",
out_one_line_file_path="../out/can_tickers_swing_one_line",
out_rejected_file_path="../out/can_tickers_rejected.csv",
period="1y",
interval="1d",
auto_adjust=True,
batch_size=80,
sleep_seconds=1.0,
thresholds=Thresholds(
min_price=1.0,
min_avg_dollar_vol_20=1_000_000.0,
max_atr_pct_14=0.05,
max_one_day_drop_126=-0.15,
require_above_50d=True,
prefer_above_200d=True,
max_stale_days=5,
),
)
df_tradable, df_rejected = run_universe_builder(cfg)
print(df_tradable.head())Given a text file of tickers (one per line), it fetches metadata from Yahoo Finance and writes a CSV with:
tickerexchangecompany_namealiases(ticker without exchange suffix, e.g.RY.TO -> RY)sectoraverage_volumemarket_caplast_pricespread_estimate
spread_estimate is computed as ask - bid when both are available; otherwise it falls back to fallback_spread_pct * last_price (default: 1%).
Run it from repo root:
python py/tickers_info.py --input data/can_tickers --out out/can_tickers_info.csvOptional arguments:
--fallback-spread-pct(default0.01)--batch-size(default80)--sleep(default1.0seconds)
out/can_tickers_info.csv- one row per ticker with metadata + liquidity-related fields
The screener is designed to find names that are:
- liquid enough to trade (proxy: price × volume)
- not too volatile for practical swing stops (ATR% constraint)
- not obviously “falling off a cliff” (worst 1-day drop over ~6 months)
- preferably aligned with trend (above key moving averages)
- showing some relative strength vs a benchmark (default:
XIU.TO) - avoiding stale/illiquid tickers (last bar not too old)
Key thresholds (defaults in Thresholds):
-
min_price
Minimum last close (default1.0) -
min_avg_dollar_vol_20
20-day average dollar volume proxy (default1,000,000) -
max_atr_pct_14
14-day ATR normalized by price (default0.05= 5%) -
max_one_day_drop_126
Worst daily return over ~126 trading days (default-0.15) -
require_above_50d
Hard gate: require above SMA50 (defaultTrue) -
prefer_above_200d
Soft preference: above SMA200 boosts score (defaultTrue) -
max_stale_days
Reject if last bar is older than N trading days (default5)
Also included:
- Volume trend check (
vol_sma20 > vol_sma50) - Relative strength vs benchmark (
rs_1m,rs_3m) - SMA50 slope normalized by mean price (cross-ticker comparable)
After a run, you’ll have:
-
out/can_tickers_swing- one ticker per line (easy to load)
-
out/can_tickers_swing_one_line- single line, comma-separated tickers
-
out/can_tickers_rejected.csv- rejected symbols + one or more
reject_reasons
- rejected symbols + one or more
Tip: when tuning thresholds, the rejected CSV is the fastest way to see why names are failing.
- The script uses
auto_adjust=Trueby default to reduce issues from splits/dividends when computing SMA/ATR/returns. - Yahoo data can be missing or inconsistent for some tickers; the code guards against common failure modes and tracks rejections.
This repo is intended to be a shared hub for finance-related tooling.
-
Stage Radar: https://github.com/ChernyshovYuriy/stage-radar
-
Point & Figure System: https://github.com/ChernyshovYuriy/pfsystem
-
TSX Canadian Stock Screener: https://github.com/ChernyshovYuriy/stock-scanner
- MIT