114 lines
2.9 KiB
Python
114 lines
2.9 KiB
Python
# engine/ledger.py
|
|
from datetime import datetime, timezone
|
|
|
|
from indian_paper_trading_strategy.engine.db import insert_engine_event, run_with_retry, get_context
|
|
from indian_paper_trading_strategy.engine.time_utils import normalize_logical_time
|
|
|
|
|
|
def _event_exists_in_tx(cur, event, logical_time, user_id: str | None = None, run_id: str | None = None):
|
|
scope_user, scope_run = get_context(user_id, run_id)
|
|
logical_ts = normalize_logical_time(logical_time)
|
|
cur.execute(
|
|
"""
|
|
SELECT 1
|
|
FROM event_ledger
|
|
WHERE user_id = %s AND run_id = %s AND event = %s AND logical_time = %s
|
|
LIMIT 1
|
|
""",
|
|
(scope_user, scope_run, event, logical_ts),
|
|
)
|
|
return cur.fetchone() is not None
|
|
|
|
|
|
def event_exists(event, logical_time, *, cur=None, user_id: str | None = None, run_id: str | None = None):
|
|
if cur is not None:
|
|
return _event_exists_in_tx(cur, event, logical_time, user_id=user_id, run_id=run_id)
|
|
|
|
def _op(cur, _conn):
|
|
return _event_exists_in_tx(cur, event, logical_time, user_id=user_id, run_id=run_id)
|
|
|
|
return run_with_retry(_op)
|
|
|
|
|
|
def _log_event_in_tx(
|
|
cur,
|
|
event,
|
|
payload,
|
|
ts,
|
|
logical_time=None,
|
|
user_id: str | None = None,
|
|
run_id: str | None = None,
|
|
):
|
|
scope_user, scope_run = get_context(user_id, run_id)
|
|
logical_ts = normalize_logical_time(logical_time or ts)
|
|
cur.execute(
|
|
"""
|
|
INSERT INTO event_ledger (
|
|
user_id,
|
|
run_id,
|
|
timestamp,
|
|
logical_time,
|
|
event,
|
|
nifty_units,
|
|
gold_units,
|
|
nifty_price,
|
|
gold_price,
|
|
amount
|
|
)
|
|
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
|
|
ON CONFLICT DO NOTHING
|
|
""",
|
|
(
|
|
scope_user,
|
|
scope_run,
|
|
ts,
|
|
logical_ts,
|
|
event,
|
|
payload.get("nifty_units"),
|
|
payload.get("gold_units"),
|
|
payload.get("nifty_price"),
|
|
payload.get("gold_price"),
|
|
payload.get("amount"),
|
|
),
|
|
)
|
|
if cur.rowcount:
|
|
insert_engine_event(cur, event, data=payload, ts=ts)
|
|
|
|
|
|
def log_event(
|
|
event,
|
|
payload,
|
|
*,
|
|
cur=None,
|
|
ts=None,
|
|
logical_time=None,
|
|
user_id: str | None = None,
|
|
run_id: str | None = None,
|
|
):
|
|
now = ts or logical_time or datetime.utcnow().replace(tzinfo=timezone.utc)
|
|
if cur is not None:
|
|
_log_event_in_tx(
|
|
cur,
|
|
event,
|
|
payload,
|
|
now,
|
|
logical_time=logical_time,
|
|
user_id=user_id,
|
|
run_id=run_id,
|
|
)
|
|
return
|
|
|
|
def _op(cur, _conn):
|
|
_log_event_in_tx(
|
|
cur,
|
|
event,
|
|
payload,
|
|
now,
|
|
logical_time=logical_time,
|
|
user_id=user_id,
|
|
run_id=run_id,
|
|
)
|
|
|
|
return run_with_retry(_op)
|
|
|