Co-authored-by: genichin <4282227+genichin@users.noreply.github.com>
99 lines
2.6 KiB
Python
99 lines
2.6 KiB
Python
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
from datetime import datetime
|
|
from uuid import UUID
|
|
|
|
from trex_core.application.alarm_emitter import AlarmEmitter
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class LedgerSkipRecord:
|
|
skip_key: str
|
|
instance_key: str
|
|
slot_id: UUID
|
|
portfolio_id: str | None
|
|
symbol: str | None
|
|
order_id: str | None
|
|
execution_id: str | None
|
|
side: str
|
|
qty: float
|
|
price: float
|
|
executed_at: datetime
|
|
order_venue: str
|
|
execution_venue: str
|
|
skip_reason: str
|
|
status: str
|
|
resolution_reason: str | None
|
|
resolved_at: datetime | None
|
|
created_at: datetime
|
|
updated_at: datetime
|
|
|
|
|
|
def make_ledger_skip_key(
|
|
*,
|
|
instance_key: str,
|
|
slot_id: UUID,
|
|
side: str,
|
|
order_id: str | None,
|
|
execution_id: str | None,
|
|
skip_reason: str,
|
|
) -> str:
|
|
return ":".join(
|
|
[
|
|
"ledger-skip",
|
|
instance_key,
|
|
str(slot_id),
|
|
side,
|
|
order_id or "-",
|
|
execution_id or "-",
|
|
skip_reason,
|
|
]
|
|
)
|
|
|
|
|
|
def ledger_skip_alarm_fields(record: LedgerSkipRecord) -> dict[str, object]:
|
|
return {
|
|
"skip_key": record.skip_key,
|
|
"instance_key": record.instance_key,
|
|
"slot_id": str(record.slot_id),
|
|
"portfolio_id": record.portfolio_id,
|
|
"symbol": record.symbol,
|
|
"order_id": record.order_id,
|
|
"execution_id": record.execution_id,
|
|
"side": record.side,
|
|
"qty": record.qty,
|
|
"price": record.price,
|
|
"executed_at": record.executed_at.isoformat(),
|
|
"order_venue": record.order_venue,
|
|
"execution_venue": record.execution_venue,
|
|
"skip_reason": record.skip_reason,
|
|
"status": record.status,
|
|
"resolution_reason": record.resolution_reason,
|
|
"resolved_at": record.resolved_at.isoformat() if record.resolved_at else None,
|
|
"created_at": record.created_at.isoformat(),
|
|
"updated_at": record.updated_at.isoformat(),
|
|
}
|
|
|
|
|
|
def publish_ledger_skip_alarm(
|
|
alarm_emitter: AlarmEmitter | None,
|
|
record: LedgerSkipRecord,
|
|
*,
|
|
resolved: bool,
|
|
) -> None:
|
|
if alarm_emitter is None:
|
|
return
|
|
code = "ledger_skip_resolved" if resolved else "ledger_skip_unresolved"
|
|
title = (
|
|
f"원장 skip 해소: slot={record.slot_id} reason={record.resolution_reason or 'resolved'}"
|
|
if resolved
|
|
else f"원장 skip 발생: slot={record.slot_id} reason={record.skip_reason}"
|
|
)
|
|
alarm_emitter.publish_alarm(
|
|
code,
|
|
title,
|
|
fields=ledger_skip_alarm_fields(record),
|
|
severity="info" if resolved else "critical",
|
|
)
|