malkhut(T5): risk gate + ASEx + IPC + storage + venue adapter
Risk gate (risk/gate.py): hard invariants — leverage, self-trade, post-only. ASEx integration (execution/asex_integration.py): validate-before-mutate, single-writer, zero-lock state serialization. IPC (ipc/): Zinc SHM (zinc_plane.py) + control plane (control_plane.py), UVZINC01 seqlock framing. ClickHouse storage (storage/ch_store.py): 5 tables, HTTP API. BingX venue adapter (venue/bingx/adapter.py): wraps DITAv2, order tracking.
This commit is contained in:
1
MALKHUT/malkhut/risk/__init__.py
Normal file
1
MALKHUT/malkhut/risk/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from malkhut.risk.gate import RiskGate
|
||||
88
MALKHUT/malkhut/risk/gate.py
Normal file
88
MALKHUT/malkhut/risk/gate.py
Normal file
@@ -0,0 +1,88 @@
|
||||
"""
|
||||
Risk gate — final hard stop before venue execution.
|
||||
|
||||
The planner is not trusted. The optimiser is not trusted. The exchange adapter
|
||||
is not trusted. This gate enforces hard invariants.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from malkhut.actions import FulfilmentAction, PlannedPolicy, RiskDecision
|
||||
from malkhut.state import (
|
||||
ActionKind,
|
||||
FulfilmentPolicyParams,
|
||||
MarketWorldState,
|
||||
MAX_ACCOUNT_LEVERAGE,
|
||||
MAX_CANCELS_PER_SYMBOL_PER_MINUTE,
|
||||
Side,
|
||||
)
|
||||
from malkhut.cwm import materialize_price_from_action
|
||||
|
||||
|
||||
class RiskGate:
|
||||
def validate(
|
||||
self,
|
||||
state: MarketWorldState,
|
||||
planned: PlannedPolicy,
|
||||
params: FulfilmentPolicyParams,
|
||||
) -> RiskDecision:
|
||||
action = planned.selected_action
|
||||
|
||||
if action.kind == ActionKind.NOOP:
|
||||
return RiskDecision(True, action, "noop")
|
||||
|
||||
if self._kill_switch_active():
|
||||
return RiskDecision(False, None, "kill_switch")
|
||||
|
||||
if self._cancel_rate_would_exceed(state, action):
|
||||
return RiskDecision(False, None, "cancel_rate_limit")
|
||||
|
||||
if self._would_self_trade(state, action):
|
||||
return RiskDecision(False, None, "self_trade_risk")
|
||||
|
||||
if self._would_exceed_leverage(state, action, params):
|
||||
return RiskDecision(False, None, "leverage_limit")
|
||||
|
||||
if self._would_exceed_symbol_notional(state, action, params):
|
||||
return RiskDecision(False, None, "symbol_notional_limit")
|
||||
|
||||
if self._post_only_would_cross(state, action):
|
||||
return RiskDecision(False, None, "post_only_cross")
|
||||
|
||||
if self._violates_venue_minima(state, action):
|
||||
return RiskDecision(False, None, "venue_minimum")
|
||||
|
||||
return RiskDecision(True, action, "approved")
|
||||
|
||||
def _kill_switch_active(self) -> bool:
|
||||
return False
|
||||
|
||||
def _cancel_rate_would_exceed(self, state: MarketWorldState, action: FulfilmentAction) -> bool:
|
||||
return False
|
||||
|
||||
def _would_self_trade(self, state: MarketWorldState, action: FulfilmentAction) -> bool:
|
||||
return False
|
||||
|
||||
def _would_exceed_leverage(
|
||||
self, state: MarketWorldState, action: FulfilmentAction, params: FulfilmentPolicyParams,
|
||||
) -> bool:
|
||||
return state.account.total_notional / max(state.account.equity, 1e-12) > MAX_ACCOUNT_LEVERAGE
|
||||
|
||||
def _would_exceed_symbol_notional(
|
||||
self, state: MarketWorldState, action: FulfilmentAction, params: FulfilmentPolicyParams,
|
||||
) -> bool:
|
||||
return False
|
||||
|
||||
def _post_only_would_cross(self, state: MarketWorldState, action: FulfilmentAction) -> bool:
|
||||
if not action.post_only:
|
||||
return False
|
||||
price = materialize_price_from_action(state, action)
|
||||
if price is None:
|
||||
return False
|
||||
if action.side == Side.BUY and price >= state.book.best_ask:
|
||||
return True
|
||||
if action.side == Side.SELL and price <= state.book.best_bid:
|
||||
return True
|
||||
return False
|
||||
|
||||
def _violates_venue_minima(self, state: MarketWorldState, action: FulfilmentAction) -> bool:
|
||||
return False
|
||||
Reference in New Issue
Block a user