Fix `SymbologyCache.search()` key matching
RapidFuzz treated `mktmaps` values as fuzzy choices and called `len()` on `MktPair` structs during paper-ledger persistence. Search string keys explicitly and resolve each match back to its struct so native market-ID aliases survive legacy FQME qualification. Also, - cover alias preservation and the paper-ledger TOML round trip. Prompt-IO: ai/prompt-io/opencode/20260828T013057Z_6ca6ab2a_prompt_io.md (this patch was generated in some part by `opencode` using `gpt-5.6-sol` (`openai`))wkt/fsp_backfill_sync
parent
6ca6ab2a10
commit
7b51927f6b
|
|
@ -0,0 +1,35 @@
|
|||
---
|
||||
model: openai/gpt-5.6-sol
|
||||
service: opencode
|
||||
session: opencode-pid-469264
|
||||
timestamp: 2026-08-28T01:30:57Z
|
||||
git_ref: 6ca6ab2a
|
||||
scope: code
|
||||
substantive: true
|
||||
raw_file: 20260828T013057Z_6ca6ab2a_prompt_io.raw.md
|
||||
---
|
||||
|
||||
## Prompt
|
||||
|
||||
Investigate Piker's clearing, accounting, order-control, and
|
||||
trade-ledger flows in depth while fixing a paper-engine crash where
|
||||
RapidFuzz called `len()` on a `MktPair` during ledger persistence.
|
||||
|
||||
## Response summary
|
||||
|
||||
Changed `SymbologyCache.search()` to fuzzy-match table keys instead of
|
||||
struct values, preserving matched aliases and preventing the paper
|
||||
trade dialog from crashing when qualifying legacy ledger FQMEs. Added
|
||||
an end-to-end regression for the implicated ledger-write path.
|
||||
|
||||
## Files changed
|
||||
|
||||
- `piker/data/_symcache.py` - searches string keys and resolves values.
|
||||
- `tests/test_accounting.py` - covers aliases and paper-ledger writes.
|
||||
|
||||
## Human edits
|
||||
|
||||
The human supplied the production traceback, identified the affected
|
||||
subsystems, and directed an implementation-level fix with deep system
|
||||
familiarization. No follow-up correction or direct manual source edit
|
||||
was identified during this interaction.
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
---
|
||||
model: openai/gpt-5.6-sol
|
||||
service: opencode
|
||||
timestamp: 2026-08-28T01:30:57Z
|
||||
git_ref: 6ca6ab2a
|
||||
diff_cmd: git diff HEAD~1..HEAD
|
||||
---
|
||||
|
||||
## Prompt
|
||||
|
||||
Become familiar with Piker's clearing, accounting, order-control,
|
||||
and trade-ledger tracking subsystems in deep detail while fixing a
|
||||
paper-engine crash. The supplied traceback showed
|
||||
`TransactionLedger.write_config()` calling
|
||||
`SymbologyCache.search()`, followed by RapidFuzz raising
|
||||
`TypeError: object of type 'MktPair' has no len()` after a paper fill.
|
||||
|
||||
## Response
|
||||
|
||||
Fixed the crash at the symbology-cache contract boundary.
|
||||
`SymbologyCache.search()` now fuzzy-matches the selected table's
|
||||
string keys and resolves each matched key back to its struct value.
|
||||
RapidFuzz therefore never receives `MktPair` values as sequences,
|
||||
and native market-ID aliases remain intact in search results.
|
||||
|
||||
> `git diff HEAD~1..HEAD -- piker/data/_symcache.py`
|
||||
|
||||
Added a regression that recreates the failing paper-ledger write with
|
||||
an unqualified Binance perpetual FQME. It also checks a native market-ID
|
||||
alias, preventing a weaker `processor=str` workaround that would lose
|
||||
the actual matched key.
|
||||
|
||||
> `git diff HEAD~1..HEAD -- tests/test_accounting.py`
|
||||
|
||||
Verification:
|
||||
|
||||
`./py313/bin/python -m pytest -p no:xonsh -q -x --tb=short
|
||||
--no-header tests/test_accounting.py::test_account_file_default_empty
|
||||
tests/test_accounting.py::test_paper_ledger_fuzzy_qualifies_mktmap_keys`
|
||||
|
||||
Result: `2 passed in 0.02s`.
|
||||
|
||||
`git diff --check` also passed. Ruff was not available in the existing
|
||||
`py313` environment, so no environment provisioning was performed.
|
||||
|
|
@ -334,15 +334,16 @@ class SymbologyCache(Struct):
|
|||
matches in a `dict` including the `MktPair` values.
|
||||
|
||||
'''
|
||||
entries: dict[str, Struct] = getattr(self, table)
|
||||
matches = fuzzy.extract(
|
||||
pattern,
|
||||
getattr(self, table),
|
||||
list(entries),
|
||||
score_cutoff=50,
|
||||
)
|
||||
|
||||
# repack in dict[fqme, MktPair] form
|
||||
return {
|
||||
item[0].fqme: item[0]
|
||||
item[0]: entries[item[0]]
|
||||
for item in matches
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,20 +5,26 @@
|
|||
- config file IO
|
||||
|
||||
'''
|
||||
from decimal import Decimal
|
||||
from pathlib import Path
|
||||
from types import ModuleType
|
||||
import tomllib
|
||||
|
||||
import pytest
|
||||
from piker import config
|
||||
from piker.accounting import (
|
||||
Account,
|
||||
Asset,
|
||||
calc,
|
||||
open_account,
|
||||
load_account,
|
||||
load_account_from_ledger,
|
||||
MktPair,
|
||||
open_trade_ledger,
|
||||
Position,
|
||||
TransactionLedger,
|
||||
)
|
||||
from piker.data._symcache import SymbologyCache
|
||||
import tractor
|
||||
|
||||
|
||||
|
|
@ -47,6 +53,82 @@ def test_account_file_default_empty(
|
|||
assert path.parent.name == 'accounting'
|
||||
|
||||
|
||||
def test_paper_ledger_fuzzy_qualifies_mktmap_keys(
|
||||
tmp_path: Path,
|
||||
):
|
||||
'''
|
||||
Qualify legacy paper-ledger FQMEs via symcache string keys.
|
||||
|
||||
``SymbologyCache.search()`` previously passed its ``mktmaps``
|
||||
mapping directly to RapidFuzz. RapidFuzz searches mapping values,
|
||||
so a paper fill with an unqualified FQME made RapidFuzz call
|
||||
``len()`` on a ``MktPair`` while
|
||||
``TransactionLedger.write_config()`` exited.
|
||||
This test installs both native-ID and FQME keys for one market,
|
||||
proves search preserves the matched alias, then writes the same
|
||||
unqualified paper transaction shape. The persisted fully
|
||||
qualified keys prove the ledger exit path resolves the market
|
||||
without treating ``MktPair`` values as fuzzy-search sequences.
|
||||
|
||||
'''
|
||||
usdt = Asset(
|
||||
name='usdt',
|
||||
atype='crypto',
|
||||
tx_tick=Decimal('0.00000001'),
|
||||
)
|
||||
nvda = Asset(
|
||||
name='nvda',
|
||||
atype='stock',
|
||||
tx_tick=Decimal('0.00000001'),
|
||||
)
|
||||
mkt = MktPair(
|
||||
dst=nvda,
|
||||
src=usdt,
|
||||
price_tick=Decimal('0.01'),
|
||||
size_tick=Decimal('0.001'),
|
||||
bs_mktid='NVDAUSDT',
|
||||
broker='binance',
|
||||
venue='usdtm',
|
||||
expiry='perp',
|
||||
)
|
||||
symcache = SymbologyCache(
|
||||
mod=ModuleType('binance'),
|
||||
fp=tmp_path / 'binance.symcache.toml',
|
||||
mktmaps={
|
||||
mkt.bs_mktid: mkt,
|
||||
mkt.fqme: mkt,
|
||||
},
|
||||
)
|
||||
|
||||
matches = symcache.search(mkt.bs_mktid)
|
||||
assert next(iter(matches)) == mkt.bs_mktid
|
||||
assert matches[mkt.bs_mktid] is mkt
|
||||
|
||||
ledger_path = tmp_path / 'trades_binance_paper.toml'
|
||||
unqualified_fqme = 'nvdausdt.usdtm.perp'
|
||||
ledger = TransactionLedger(
|
||||
ledger_dict={
|
||||
'fill-id': {
|
||||
'fqme': unqualified_fqme,
|
||||
'bs_mktid': unqualified_fqme,
|
||||
},
|
||||
},
|
||||
file_path=ledger_path,
|
||||
account='paper',
|
||||
mod=symcache.mod,
|
||||
tx_sort=lambda txns: txns.items(),
|
||||
symcache=symcache,
|
||||
)
|
||||
|
||||
ledger.write_config()
|
||||
|
||||
with ledger_path.open('rb') as ledger_file:
|
||||
saved = tomllib.load(ledger_file)['fill-id']
|
||||
|
||||
assert saved['fqme'] == mkt.fqme
|
||||
assert saved['bs_mktid'] == mkt.fqme
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'fq_acnt',
|
||||
[
|
||||
|
|
|
|||
Loading…
Reference in New Issue