feat: Introduce `p30_live_guard` with positive and negative checks, add `policy_codes` for CCXT shim, and allow `p29_real_mode_
parent
cf2ad27d34
commit
f4b72a745d
@ -0,0 +1,34 @@
|
||||
"""
|
||||
Policy Codes for BreezeCCXT Shim.
|
||||
Defines standardized blocking codes that should NOT trigger Degraded Mode.
|
||||
"""
|
||||
|
||||
|
||||
class PolicyCode:
|
||||
LIVE_BLOCKED = "Live Trading Guard: Blocked"
|
||||
MARKET_CLOSED = "market_closed"
|
||||
RISK_BLOCK = "risk_block"
|
||||
DEGRADED_BLOCK = "degraded_block"
|
||||
|
||||
# Legacy/Fallback
|
||||
LIVE_BLOCKED_UC = "LIVE_BLOCKED"
|
||||
|
||||
|
||||
# Set of codes that represent intentional safety blocks, not system failures.
|
||||
SAFETY_BLOCKS = {
|
||||
PolicyCode.LIVE_BLOCKED,
|
||||
PolicyCode.MARKET_CLOSED,
|
||||
PolicyCode.RISK_BLOCK,
|
||||
PolicyCode.DEGRADED_BLOCK,
|
||||
PolicyCode.LIVE_BLOCKED_UC,
|
||||
}
|
||||
|
||||
|
||||
def is_safety_block(message: str) -> bool:
|
||||
"""
|
||||
Check if an exception message corresponds to a safety block.
|
||||
"""
|
||||
for code in SAFETY_BLOCKS:
|
||||
if code in message:
|
||||
return True
|
||||
return False
|
||||
@ -0,0 +1,61 @@
|
||||
import sys
|
||||
import os
|
||||
from unittest.mock import MagicMock
|
||||
import logging
|
||||
|
||||
# Ensure project root is in path
|
||||
sys.path.append(os.getcwd())
|
||||
|
||||
from adapters.ccxt_shim.breeze_ccxt import BreezeCCXT
|
||||
from freqtrade.exceptions import OperationalException
|
||||
|
||||
|
||||
def check_p30_neg():
|
||||
# Setup Logger
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger("p30_neg")
|
||||
|
||||
print(">>> P30 Neg: Testing Guard Layering (Double Lock Open + Market Closed)...")
|
||||
|
||||
# 1. Open Double Lock
|
||||
os.environ["FT_ENABLE_LIVE_ORDERS"] = "1"
|
||||
|
||||
# 2. Force Market Closed
|
||||
os.environ["FT_FORCE_MARKET_CLOSED"] = "1"
|
||||
|
||||
config = {
|
||||
"icicibreeze": {"live_trading": {"enabled": True}},
|
||||
"options": {"key": "test", "secret": "test", "session_token": "test"},
|
||||
"pair_whitelist": ["RELIANCE/INR"],
|
||||
}
|
||||
|
||||
exchange = BreezeCCXT(config)
|
||||
# Mock ticker
|
||||
exchange.fetch_ticker = lambda symbol, params=None: {
|
||||
"symbol": symbol,
|
||||
"last": 2500.0,
|
||||
"bid": 2499.0,
|
||||
"ask": 2501.0,
|
||||
}
|
||||
# Mock SDK just in case (should not be reached)
|
||||
exchange.breeze = MagicMock()
|
||||
|
||||
try:
|
||||
exchange.create_order("RELIANCE/INR", "limit", "buy", 1, 2500.0)
|
||||
print("ERROR: Order was Allowed! (Should be blocked by Market Hours)")
|
||||
sys.exit(1)
|
||||
except Exception as e:
|
||||
msg = str(e)
|
||||
logger.exception(f"Caught Expected Exception: {msg}")
|
||||
|
||||
if "market_closed" in msg and "blocking entry" in msg:
|
||||
print("P30_NEG_EXPECTED_BLOCK")
|
||||
print("[OK] Blocked by Market Hours despite Live Enablement.")
|
||||
sys.exit(0)
|
||||
else:
|
||||
print(f"ERROR: Unexpected exception: {msg}")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
check_p30_neg()
|
||||
Loading…
Reference in new issue