feat(analytics): брокерские потоки по месяцам и порядок шагов пересчёта
cashflow_broker читает event заново по EXTERNAL_FLOW_KINDS, а не агрегирует готовый external_flow_rub. Дневная серия неттит потоки по (счёт, валюта, день) ДО конвертации, поэтому пополнение и вывод одного дня схлопываются, и разбивку из неё не восстановить: на живых данных так спрятано 512 550 ₽ выводов, и все 40 месяцев выглядели бы как «только пополнения». Правила чтения скопированы из valuation._load_deltas один в один, поэтому net сходится с external_flow_rub по всем 40 месяцам до последнего знака. Месяц без потоков строки не порождает: разрежённый ряд позволяет клиенту отличить «ничего не было» от «вышло в ноль», а дорисовать нули он может сам. Порядок шагов: fx → classify → matching → corpactions → lots → … → cashflow_broker → networth → …. matching строго ПОСЛЕ classify, потому что classify пересчитывает flow_type всех транзакций с нуля из правил и затёр бы internal_transfer, проставленный линковкой; и строго ДО networth и cashflow, которые этот flow_type читают. corpactions строго ДО lots: rebuild._split_ratios берёт коэффициенты из corporate_action.
This commit is contained in:
@@ -2,7 +2,8 @@
|
||||
|
||||
The steps are registered on `metrics.refresh.STEPS` in the order they must run:
|
||||
|
||||
fx -> classify -> networth -> cashflow -> spending -> runway -> quality
|
||||
fx -> classify -> matching -> corpactions -> lots -> valuation -> returns -> allocation
|
||||
-> cashflow_broker -> networth -> cashflow -> spending -> runway -> quality
|
||||
|
||||
Registration happens lazily from `refresh_all` (see `register_steps`) so importing
|
||||
`fintracker.metrics.refresh` stays free of the analytics import graph.
|
||||
@@ -103,6 +104,7 @@ def register_steps() -> None:
|
||||
from fintracker.analytics import (
|
||||
allocation,
|
||||
cashflow,
|
||||
cashflow_broker,
|
||||
classify,
|
||||
networth,
|
||||
quality,
|
||||
@@ -111,17 +113,25 @@ def register_steps() -> None:
|
||||
spending,
|
||||
valuation,
|
||||
)
|
||||
from fintracker.ledger.corporate_actions import rebuild_corporate_actions
|
||||
from fintracker.ledger.matching import rebuild_flow_links
|
||||
from fintracker.ledger.rebuild import rebuild_lots
|
||||
from fintracker.metrics.refresh import register_step
|
||||
|
||||
register_step("fx", _step_fx)
|
||||
register_step("classify", classify.rebuild_classification)
|
||||
# matching must follow classify, never precede it: classify recomputes every flow_type
|
||||
# from the rules, so a link's `internal_transfer` written earlier would be overwritten
|
||||
register_step("matching", rebuild_flow_links)
|
||||
# splits and amortisations are what lots consume, so they have to exist first
|
||||
register_step("corpactions", rebuild_corporate_actions)
|
||||
# lots need FX (cost in RUB at the open date) and feed every later valuation step
|
||||
register_step("lots", rebuild_lots)
|
||||
# valuation prices the positions the lots describe; returns reads the series it writes
|
||||
register_step("valuation", valuation.rebuild_valuation)
|
||||
register_step("returns", returns.rebuild_returns)
|
||||
register_step("allocation", allocation.rebuild_allocation)
|
||||
register_step("cashflow_broker", cashflow_broker.rebuild_cash_flow_broker)
|
||||
register_step("networth", networth.rebuild_net_worth_daily)
|
||||
register_step("cashflow", cashflow.rebuild_cash_flow_monthly)
|
||||
register_step("spending", spending.rebuild_spending_by_category)
|
||||
|
||||
Reference in New Issue
Block a user