Automatic flex query syncing

This commit is contained in:
2026-04-01 23:28:51 -05:00
parent aa872aba67
commit cfe00f67b5
6 changed files with 145 additions and 16 deletions

View File

@@ -29,12 +29,18 @@ class FlexConfig:
data_dir: Path
poll_interval_seconds: float = 2.0
max_polls: int = 30
send_request_retry_seconds: float = 10.0
max_send_request_attempts: int = 6
class FlexQueryError(RuntimeError):
pass
class FlexQueryRetryableError(FlexQueryError):
pass
def load_flex_config() -> FlexConfig | None:
token = os.environ.get("IB_FLEX_TOKEN", "").strip()
query_id = os.environ.get("IB_FLEX_QUERY_ID", "").strip()
@@ -86,7 +92,11 @@ def _parse_send_request(xml_bytes: bytes) -> tuple[str, str]:
root = ET.fromstring(xml_bytes)
status = (root.findtext("Status") or "").strip()
if status.lower() != "success":
raise FlexQueryError(root.findtext("ErrorMessage") or "Flex send-request failed")
error_code = (root.findtext("ErrorCode") or "").strip()
error_message = (root.findtext("ErrorMessage") or "Flex send-request failed").strip()
if error_code == "1004":
raise FlexQueryRetryableError(error_message)
raise FlexQueryError(error_message)
reference_code = (root.findtext("ReferenceCode") or "").strip()
if not reference_code:
raise FlexQueryError("Flex send-request returned no ReferenceCode")
@@ -110,10 +120,23 @@ def fetch_flex_statement() -> dict:
config.data_dir.mkdir(parents=True, exist_ok=True)
_, reference_code = _parse_send_request(_http_get(
FLEX_SEND_REQUEST_URL,
{"t": config.token, "q": config.query_id, "v": "3"},
))
reference_code = None
last_retryable_error = None
for attempt in range(1, config.max_send_request_attempts + 1):
try:
_, reference_code = _parse_send_request(_http_get(
FLEX_SEND_REQUEST_URL,
{"t": config.token, "q": config.query_id, "v": "3"},
))
break
except FlexQueryRetryableError as exc:
last_retryable_error = str(exc)
if attempt >= config.max_send_request_attempts:
raise FlexQueryError(last_retryable_error) from exc
time.sleep(config.send_request_retry_seconds)
if not reference_code:
raise FlexQueryError(last_retryable_error or "Flex send-request returned no ReferenceCode")
statement_xml = None
for _ in range(config.max_polls):