Skip to main content

Find the affine transform that maps a candidate ticker's price series onto a familiar chart shape, and screen tickers that 'look like' a setup.

Project description

chart-lookalike-transform

Find the affine transform — vertical scale a, offset b, and optional inversion — that best maps a candidate ticker's price series onto a chart shape you already recognize, then screen a list of tickers by how well they "look like" that setup.

A chart's shape is invariant to vertical scale and shift: $10 → $11 over a month traces the same curve as $100 → $110. So to ask "does NVDA right now look like the cup-and-handle I'm watching for?" you fit

reference ≈ a · candidate + b          (a < 0 ⇒ candidate is the mirror image)

by least squares (closed form), report the fit quality as a 0..1 similarity, and overlay the transformed candidate on the reference with moving-average indicators.

This is not dynamic time warping — the time axis is held fixed, so "lookalike" means the literal same shape over the same window, just rescaled vertically. (DTW would match shapes that drift in time; deliberately out of scope.)

Install

pip install -e ".[test]"      # includes matplotlib for plotting + pytest
# or, runtime only:
pip install -e .              # numpy only; add ".[plot]" for PNG overlays

Python ≥ 3.10. Core dependency is just NumPy; matplotlib is optional (only for --plot).

Quick start (no network)

Everything works offline against deterministic synthetic data via --offline (or CHART_LOOKALIKE_API=mock), so you can try it instantly:

# List the built-in reference shapes.
chart-lookalike shapes

# Fit one ticker to a recognized shape and print the transform.
chart-lookalike match AAPL --shape cup-with-handle --offline

# Screen a basket, keep the best 5, and use a real ticker as the reference shape.
chart-lookalike screen AAPL MSFT NVDA TSLA AMD --ref-ticker NVDA --offline --top 5

# Write a PNG overlay (transformed candidate + reference + SMAs).
chart-lookalike match TSLA --shape v-bottom --offline --plot match.png

Drop --offline to pull live daily closes from Yahoo Finance (no API key needed). The data layer is provider-pluggable behind the CHART_LOOKALIKE_API env var.

Reference shapes

Three ways to specify the target shape (choose exactly one):

Flag Meaning
--shape <name> a built-in shape (chart-lookalike shapes lists them)
--ref-csv <path> a file of reference prices (one number per line, or date,close rows — the last numeric field per line is used)
--ref-ticker <sym> use another ticker's own series as the target shape

Built-in shapes: v-bottom, inverse-v-top, cup, cup-with-handle, head-and-shoulders, uptrend, downtrend, double-bottom.

How the fit works

For a reference t and candidate c (resampled to a common length), the least-squares affine fit has a closed form:

a = cov(c, t) / var(c)
b = mean(t) − a · mean(c)

When inversion is allowed, the mirror candidate −c is also fit and the lower-residual solution wins (a negative ainverted = True). Fit quality:

rmse       = sqrt( mean( (a·c + b − t)² ) )
similarity = clip( 1 − rmse / rms(t − mean(t)),  0, 1 )

similarity = 1.0 is a perfect shape match; 0.0 is no better than predicting a flat line at the reference's mean.

Library API

import numpy as np
from chart_lookalike import fit_affine, apply_affine, get_provider, screen
from chart_lookalike.shapes import get_shape

provider = get_provider("mock")              # or "yahoo"
series   = provider.history("AAPL", days=180)
ref      = get_shape("cup-with-handle")

fit = fit_affine(series.closes, ref)         # AffineFit(scale, offset, inverted, rmse, similarity, n)
overlay = apply_affine(series.closes, fit)   # candidate mapped onto the reference's units

ranked = screen(ref, ["AAPL", "MSFT", "NVDA"], provider, top=3)
for r in ranked:
    print(r.symbol, round(r.similarity, 3), "inverted" if r.fit.inverted else "")

Live-data dependency & testing

The Yahoo provider hits query1.finance.yahoo.com/v8/finance/chart at runtime — that endpoint is undocumented and rate-limited, so it is the one piece that can break outside our control. The JSON parser (parse_yahoo_chart) is split out as a pure function and unit-tested against a saved fixture (fixtures/yahoo_aapl.json, including a null-close hole and the error envelope) — the test suite never touches the network.

pytest -q

Disclaimer

This is a charting/screening aid, not investment advice. A high similarity score means two curves have a similar shape over a window — nothing about what happens next.

License

MIT — see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

chart_lookalike_transform-0.1.0.tar.gz (24.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

chart_lookalike_transform-0.1.0-py3-none-any.whl (19.4 kB view details)

Uploaded Python 3

File details

Details for the file chart_lookalike_transform-0.1.0.tar.gz.

File metadata

File hashes

Hashes for chart_lookalike_transform-0.1.0.tar.gz
Algorithm Hash digest
SHA256 65dfd5786e9ea4ab9945df41bc24a74fd8acb1fe24afa0febf6eb631fbee05a8
MD5 4815f923ae2c900f72c6927b4cff83da
BLAKE2b-256 a2651e93ca40b851694d180a1c1c318245e6a615186b6782cf4766483b379cd6

See more details on using hashes here.

File details

Details for the file chart_lookalike_transform-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for chart_lookalike_transform-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 1ba7898d92082b53cff0e7b786c5ce55cae654c26626151d9fbf19fbdaab740f
MD5 8805a79743729e7c83f6c703108ac7a9
BLAKE2b-256 5aed06227c89621616989e2fe4c37acce31f36571416d2f39b62fbbd88589579

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page