Skip to content

Strategies (for entertainment only)

lotterycn.predict ships eleven number-generation strategies plus a composable filter engine. None of them has any predictive power — draws are independent random events, so every strategy has exactly the same expected value as the random baseline. This module exists for statistical observation and entertainment.

Method Aliases School Idea
random — baseline Uniform random — every other strategy should be compared against it
frequency hot / cold trend charts Pick numbers by appearance frequency over a sliding window (recent_n), explore_ratio controls determinism
omission chase trend charts Mean-reversion chase: score = current omission / average omission ("hot-then-cold" numbers rank highest)
deviation chisq statistics Chi-square deviation (observed − expected)² / expected; side='hot' or 'cold'
repeat — community Repeat / neighbor (±1) / jump (second-last draw ±1) weighting — the repeat / neighbor / jump-number playbook
trend — stock framework Sum moving-average channel: random candidates kept only if their sum falls inside MA ± k·σ
tail — trend charts Two-level picks: choose tail digits (number % 10) by frequency, then numbers within those tails
markov — sequence First-order transition sampling P(appear now | appeared/not last draw) — collapses to frequency under independence
markov2 — sequence Second-order transition (last two draws, 4 states) — shows how higher-order states collapse to uniform through sparsity
filter — shape school Composable shrink engine: sum_range, odd_range, prime_range, ac_range, consecutive_range (ranges), zone_ratio & mod3_range (012-route, exact match), exclude_numbers (kill numbers)
ensemble — integration Multi-strategy voting: members each contribute a top-k ticket, numbers ranked by votes (votes_min threshold)

Usage

from lotterycn import load_predict_numbers

# method='hot' is an alias of frequency + mode='hot'
picks = load_predict_numbers("ssq", method="hot", amount=5)
chase = load_predict_numbers("ssq", method="omission", amount=3)  # mean reversion
dev = load_predict_numbers("ssq", method="deviation", side="cold", explore_ratio=0)
rep = load_predict_numbers("ssq", method="repeat", repeat_weight=3.0)
band = load_predict_numbers("ssq", method="trend", k_sigma=1.0)
shrink = load_predict_numbers(
    "ssq",
    method="filter",
    amount=3,
    sum_range=(90, 120),
    prime_range=(2, 3),
    zone_ratio=(2, 2, 2),
    exclude_numbers={7, 13},
)
votes = load_predict_numbers(
    "ssq",
    method="ensemble",
    amount=1,
    members=("frequency", "omission", "repeat"),
)

Pass history= to inject a DataFrame and work fully offline; otherwise the factory fetches draw history (respects if_cached=True).

Filter shape-metric definitions

All *_range filters are inclusive (lo, hi) intervals; zone_ratio and mod3_range are exact matches on the count triple.

  • AC value — number of distinct pairwise differences among the sorted unique numbers, minus (count − 1). Example: {01,02,06,13,27,33} has exactly 15 distinct pairwise differences, so AC = 15 − (6 − 1) = 10 (the theoretical maximum for 6 numbers); the fully consecutive {01..06} has only 5, so AC = 0.
  • Zone ratio (exact match) — the red pool is split into three zones; per-zone counts must equal the given (zone1, zone2, zone3) exactly. Zone boundaries per game:
Game (red pool) Zone 1 Zone 2 Zone 3
ssq (1-33) 1-11 12-22 23-33
qlc (1-30) 1-10 11-20 21-30
kl8 (1-80) 1-27 28-54 55-80
dlt (1-35) 1-12 13-24 25-35
digit games 3d/pls/plw/qxc (0-9) 0-3 4-6 7-9
  • 012-route mod3_range (exact match) — counts of numbers ≡ 0 / 1 / 2 (mod 3) must equal the given triple exactly.
  • Primes — {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31} (1 is not prime).
  • Consecutive pairs — adjacent pairs (differ by exactly 1) among the sorted unique numbers.

As with every strategy, filtering changes only the shape of the picked tickets — it never changes any ticket's winning probability.

Backtesting — verify the "no predictive power" claim yourself

from lotterycn import backtest, backtest_summary

results = backtest(
    methods=("random", "hot", "omission", "ensemble"),
    lottery_name="ssq",
    window=100,
)
print(backtest_summary(results))

Each strategy is driven by the preceding window draws and evaluated against the next real draw (red/blue hit counts). The expected outcome — reproduced every time — is that all strategies perform on par with random. Community machine-learning attempts (LSTM/XGBoost on number sequences) reach the same conclusion: on a Pick-3-sized space (1/1000) an LSTM lands at ≈ 4.2‰ accuracy, i.e. the baseline. Any "significantly better than random" observation should be treated as overfitting or noise.

A note on the stock-analysis analogy

Several strategies deliberately mirror stock-analysis frameworks (momentum ≈ hot numbers, mean reversion ≈ omission chase, moving-average channels ≈ trend, volume ≈ sales/pool features from draws.py). The analogy is pedagogical: in an efficient market and in a lottery, frameworks do not create edge — but they make the randomness measurable.