| Connecting a data source |
Zero-padded tickers are destroyed. The CSV connector calls
pd.read_csv(path) with no options at all, so Samsung's KRX code
005930 lands as the integer 5930 and Tencent's 00700 as
700. The universe file lists them as text, so the join then finds nothing. There is
no dtype option to prevent it — anything you put in options is silently
ignored by this connector. | Bad | W-07 fixed in 0.1.2 |
A reordered feed writes data into the wrong columns. The key is matched by
name but the insert is INSERT INTO … SELECT *, which is positional. Poll 1 sends
date,symbol,close; poll 2 sends symbol,date,close. Result: the date
column holds "A" and "B", the symbol column holds dates, and the run reports
ok. | Bad | W-08 fixed in 0.1.2 |
mode: append is the default and doubles the table every poll
when no key is set. Poll twice, get 8 rows from 4. Nothing warns — not at run time,
not in qanat check. The store.write docstring describes this exact
failure without enforcing it. | Medium | W-09 fixed in 0.1.2 |
A null in a key column defeats dedup forever. The match is
t.k = incoming.k, and in SQL null never equals null, so a row with a blank key part
is appended again on every single poll. Unbounded growth, no warning. Within one batch
drop_duplicates does collapse it — so the two halves of the same feature
disagree. | Medium | W-10 fixed in 0.1.2 |
| One bad symbol loses the whole batch. The REST connector loops per symbol
and concatenates at the end, so a single 404 discards every symbol that succeeded. One delisted
ticker stalls the feed indefinitely — every poll lands zero rows until someone edits the
list. | Medium | W-11 fixed in 0.1.2 |
mode: replace never clears when the feed goes empty.
run_source short-circuits on an empty frame and never calls write, so
the "an empty answer must clear the table" logic is unreachable from a source. The old rows stay
and read downstream as current. | Medium | W-12 fixed in 0.1.2 |
A float landing in a column pandas first typed as int is silently rounded.
First poll has whole-number closes → the column is BIGINT forever. After that
102.5 becomes 102 and a sub-dollar price becomes
0. | Medium | W-13 fixed in 0.1.2 |
A 200 response with the wrong shape replaces the price history. An expired
session returns {error, message, code} with status 200; in replace mode that lands as
the table. Two clean "ok" polls and the prices are gone. There is no schema contract on a source
anywhere. | Medium | W-14 partly fixed |
An unset ${VAR} becomes an empty string. That produces
Illegal header value b'Bearer ', or a request sent with a blank API key, or the
actively wrong message rest needs options.url when the option is set and the
environment variable is not. Lowercase ${var} is never expanded at all, and is sent
literally. | Medium | W-15 fixed in 0.1.2 |
| Reading the result |
Decay silently changes the size of the book, not just its turnover. For a
long-short book that flips sign, decay_weights returns
|weights| = 0.33 where the alpha wrote 1.00 — it averages and never
renormalises. The sibling function combine(), used for blending several alphas, does
renormalise. Two blending paths in one file, two different rules. The docstring promises "the
signal survives, the turnover falls"; a third of the exposure does not
survive. | Medium | W-16 fixed in 0.1.2 |
"What was held" is not what was priced. save_bt_weights stores
the alpha's raw output, before decay. With decay: 3 the saved book has
|weights| = 1.0 while the measured turnover proves the priced book was about
0.34. The drill-down shows a portfolio that was never
traded. | Medium | W-17 fixed in 0.1.2 |
The "weights do not sum to 1" warning never reaches the report. I ran an
alpha whose book was 1.9× the declared size. The event log says so. The report does not:
status: ok, notes: 0, failures: 0, nothing in
conditions, and a headline of 19.69% on a levered
book. | Medium | W-18 fixed in 0.1.2 |
| Duplicate symbols are silently deduped. The alpha wrote A twice (0.6 and
0.9). The replay keeps the last one and drops the other with no note, so three different book
sizes exist for one rebalance — 1.9 written, 1.3 priced, and the 1.0 the contract
expects. | Medium | W-19 fixed in 0.1.2 |
A half-failed run is ranked like a complete one. An alpha that crashes on
down days scored 71 of 152 periods — the rest failed. The store marks it partial, but
the strategy book filters only on periods > 0, so its net sits in the ranking with
no marker, and notes is empty. | Medium | W-20 fixed in 0.1.2 |
A rebalance finer than the data quietly shrinks the run. Daily rebalance on
weekly prices: 145 stops asked for, 20 scored, 125 skipped. The notes are all there and
periods honestly says 20 — but nothing up front says the run you asked for is not the
run you got. | Medium | W-21 partly fixed |