89 lines
3.0 KiB
Python
89 lines
3.0 KiB
Python
|
|
"""
|
||
|
|
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
|